From efcdc64a2a7219956823ea6f7e8c7ab7b1f245d3 Mon Sep 17 00:00:00 2001 From: Bryn Rhodes Date: Tue, 21 Apr 2020 11:11:35 -0600 Subject: [PATCH] #513: Added a JXSON format option to support using the Jackson serializer to produce JSON output. --- Src/java/build.gradle | 4 ++ .../cql/cql2elm/CqlTranslator.java | 47 +++++++++++++++++-- .../model/serialization/LibraryWrapper.java | 14 ++++++ .../cql/elm/tracking/Trackable.java | 9 ++++ 4 files changed, 71 insertions(+), 3 deletions(-) create mode 100644 Src/java/cql-to-elm/src/main/java/org/cqframework/cql/cql2elm/model/serialization/LibraryWrapper.java diff --git a/Src/java/build.gradle b/Src/java/build.gradle index 708054456..80e9248ed 100644 --- a/Src/java/build.gradle +++ b/Src/java/build.gradle @@ -116,6 +116,10 @@ configure(subprojects.findAll {it.name in ['model', 'elm', 'quick', 'qdm']}) { runtime group: 'com.sun.xml.bind', name: 'jaxb-impl', version: '2.4.0-b180830.0438' runtime group: 'javax.xml.bind', name: 'jaxb-api', version: '2.3.1' runtime group: 'com.sun.activation', name: 'javax.activation', version: '1.2.0' + runtime group: 'com.fasterxml.jackson.core', name: 'jackson-databind', version: '2.10.1' + runtime group: 'com.fasterxml.jackson.core', name: 'jackson-annotations', version: '2.10.1' + runtime group: 'com.fasterxml.jackson.core', name: 'jackson-core', version: '2.10.1' + runtime group: 'com.fasterxml.jackson.module', name: 'jackson-module-jaxb-annotations', version: '2.10.1' } ext.xjc = [ diff --git a/Src/java/cql-to-elm/src/main/java/org/cqframework/cql/cql2elm/CqlTranslator.java b/Src/java/cql-to-elm/src/main/java/org/cqframework/cql/cql2elm/CqlTranslator.java index 2168278ae..adb2475ee 100644 --- a/Src/java/cql-to-elm/src/main/java/org/cqframework/cql/cql2elm/CqlTranslator.java +++ b/Src/java/cql-to-elm/src/main/java/org/cqframework/cql/cql2elm/CqlTranslator.java @@ -1,5 +1,10 @@ package org.cqframework.cql.cql2elm; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.SerializationFeature; +import com.fasterxml.jackson.module.jaxb.JaxbAnnotationModule; import joptsimple.OptionParser; import joptsimple.OptionSet; import joptsimple.OptionSpec; @@ -7,6 +12,7 @@ import org.antlr.v4.runtime.misc.NotNull; import org.antlr.v4.runtime.tree.ParseTree; import org.cqframework.cql.cql2elm.model.TranslatedLibrary; +import org.cqframework.cql.cql2elm.model.serialization.LibraryWrapper; import org.cqframework.cql.cql2elm.preprocessor.CqlPreprocessorVisitor; import org.cqframework.cql.elm.tracking.TrackBack; import org.cqframework.cql.gen.cqlLexer; @@ -44,7 +50,7 @@ public static enum Options { DisableMethodInvocation, RequireFromKeyword } - public static enum Format { XML, JSON, COFFEE } + public static enum Format { XML, JSON, JXSON, COFFEE } private static JAXBContext jaxbContext; private Library library = null; @@ -325,10 +331,23 @@ private String toJson(Library library) { return convertToJson(library); } catch (JAXBException e) { - throw new IllegalArgumentException("Could not convert library to JSON.", e); + throw new IllegalArgumentException("Could not convert library to JSON using JAXB serializer.", e); } } + private String toJxson(Library library) { + try { + return convertToJxson(library); + } + catch (JsonProcessingException e) { + throw new IllegalArgumentException("Could not convert library to JSON using Jackson serializer.", e); + } + } + + public String toJxson() { + return toJxson(library); + } + public String toJson() { return toJson(library); } @@ -377,6 +396,14 @@ public Map getLibrariesAsJSON() { return result; } + public Map getLibrariesAsJXSON() { + Map result = new HashMap(); + for (Map.Entry entry : libraryManager.getTranslatedLibraries().entrySet()) { + result.put(entry.getKey(), toJxson(entry.getValue().getLibrary())); + } + return result; + } + public List getExceptions() { return exceptions; } public List getErrors() { return errors; } @@ -410,7 +437,6 @@ public CqlErrorListener(LibraryBuilder builder, boolean detailedErrors) { @Override public void syntaxError(@NotNull Recognizer recognizer, Object offendingSymbol, int line, int charPositionInLine, @NotNull String msg, RecognitionException e) { TrackBack trackback = new TrackBack(new VersionedIdentifier().withId("unknown"), line, charPositionInLine, line, charPositionInLine); -// CqlTranslator.this.errors.add(new CqlTranslatorException(msg, trackback, e)); if (detailedErrors) { builder.recordParsingException(new CqlSyntaxException(msg, trackback, e)); @@ -519,6 +545,17 @@ public String convertToJson(Library library) throws JAXBException { return writer.getBuffer().toString(); } + public String convertToJxson(Library library) throws JsonProcessingException { + ObjectMapper mapper = new ObjectMapper(); + mapper.setDefaultPropertyInclusion(JsonInclude.Include.NON_DEFAULT); + mapper.configure(SerializationFeature.INDENT_OUTPUT, true); + JaxbAnnotationModule annotationModule = new JaxbAnnotationModule(); + mapper.registerModule(annotationModule); + LibraryWrapper wrapper = new LibraryWrapper(); + wrapper.setLibrary(library); + return mapper.writeValueAsString(wrapper); + } + public static void loadModelInfo(File modelInfoXML) { final ModelInfo modelInfo = JAXB.unmarshal(modelInfoXML, ModelInfo.class); final VersionedIdentifier modelId = new VersionedIdentifier().withId(modelInfo.getName()).withVersion(modelInfo.getVersion()); @@ -616,6 +653,9 @@ private static void writeELM(Path inPath, Path outPath, CqlTranslator.Format for pw.print("module.exports = "); pw.println(translator.toJson()); break; + case JXSON: + pw.println(translator.toJxson()); + break; case JSON: pw.println(translator.toJson()); break; @@ -700,6 +740,7 @@ public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IO } switch (outputFormat) { case JSON: + case JXSON: name += ".json"; break; case COFFEE: diff --git a/Src/java/cql-to-elm/src/main/java/org/cqframework/cql/cql2elm/model/serialization/LibraryWrapper.java b/Src/java/cql-to-elm/src/main/java/org/cqframework/cql/cql2elm/model/serialization/LibraryWrapper.java new file mode 100644 index 000000000..2c8f6657b --- /dev/null +++ b/Src/java/cql-to-elm/src/main/java/org/cqframework/cql/cql2elm/model/serialization/LibraryWrapper.java @@ -0,0 +1,14 @@ +package org.cqframework.cql.cql2elm.model.serialization; + +import org.hl7.elm.r1.Library; + +public class LibraryWrapper { + private Library library; + public Library getLibrary() { + return this.library; + } + + public void setLibrary(Library library) { + this.library = library; + } +} diff --git a/Src/java/elm/src/main/java/org/cqframework/cql/elm/tracking/Trackable.java b/Src/java/elm/src/main/java/org/cqframework/cql/elm/tracking/Trackable.java index 04f3a4584..40f969f92 100644 --- a/Src/java/elm/src/main/java/org/cqframework/cql/elm/tracking/Trackable.java +++ b/Src/java/elm/src/main/java/org/cqframework/cql/elm/tracking/Trackable.java @@ -1,5 +1,8 @@ package org.cqframework.cql.elm.tracking; +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonTypeInfo; import org.hl7.cql.model.DataType; import javax.xml.bind.annotation.XmlTransient; @@ -7,6 +10,7 @@ import java.util.List; import java.util.UUID; +@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "type") public class Trackable { private final UUID trackerId; private final List trackbacks; @@ -18,15 +22,20 @@ public Trackable() { this.trackbacks = new ArrayList<>(); } + @XmlTransient + @JsonIgnore public UUID getTrackerId() { return trackerId; } + @XmlTransient + @JsonIgnore public List getTrackbacks() { return trackbacks; } @XmlTransient + @JsonIgnore public DataType getResultType() { return resultType; }