v3 to v4 Migration - cqframework/clinical_quality_language GitHub Wiki
This page outlines the changes to this repository that are included with the v4 release.
The #1462 pull request converted the cql-to-elm Java project and its dependencies to Kotlin Multiplatform (KMP) targeting the JVM and JavaScript. The Java translator maintains feature parity with the previous version (see the summary of changes below), while the new JS target makes it possible to convert CQL to ELM in the browser and Node.js.
Summary of changes for Java users
The Java API of the translator remains largely the same, however some changes have been made to accommodate KMP conventions.
Dependency management
- Starting with v4, the releases will be published under the new
org.cqframeworkgroup ID on Maven Central. - Previously, you needed to add
elm-(jackson|jaxb)andmodel-(jackson|jaxb)as extra dependencies to your project. This is no longer required because the default multiplatform serialization functionality is now included withcql-to-elm. Theelm-(jackson|jaxb)andmodel-(jackson|jaxb)projects have been removed. - For
ucum-java-based unit validation to work in the translator on the JVM, you now need to adducumas a dependency (a new project in this repository). Alternatively, you can provide your own implementation of theUcumServiceinterface.
Class and interface relocation, removals, and other API changes
Notable changes, grouped by the affected class or interface:
CqlTranslator:- The
fromStream()static method (all overloads) is replaced withfromSource()which acceptsSourceinstead of JavaInputStream. - The
fromFile()static method overloads now accept KMPPathinstead of JavaFile. - The
toXml(),toJson(),convertToXml(),convertToJson()methods have new overloads that additionally accept an implementation ofElmLibraryWriterProvider, allowing you to provide a custom ELM serializer.
- The
LibraryManager:- A new constructor overload additionally accepts an implementation of
ElmLibraryReaderProvider, allowing you to provide a custom ELM deserializer.
- A new constructor overload additionally accepts an implementation of
LibrarySourceProvider:- The
getLibrarySource()andgetLibraryContent()methods now returnSourceinstead of JavaInputStream.
- The
DefaultLibrarySourceProvider:- The constructor accepts KMP
Pathinstead of JavaPath.
- The constructor accepts KMP
ElmLibraryWriter:- The
write()method acceptsSinkinstead of JavaWriter.
- The
ElmLibraryReader:- The
read()overloads acceptStringorSource.
- The
- The
org.cqframework.cql.elm.tracking.(Trackable|TrackBack)classes are moved toorg.cqframework.cql.cql2elm.tracking.(Trackable|TrackBack). ModelInfoReader,ModelInfoReaderFactory,ModelInfoReaderProviderare all replaced with a single multiplatformparseModelInfoXml()method.- The
CqlTranslatorOptionsMapper.fromFile()static method is replaced withCqlTranslatorOptions.fromFile()accepting KMPPath.
cql-to-elm's new KMP project structure
One of the motivations for converting to KMP was to publish the JavaScript version of the CQL compiler. The new JS variant is now built alongside the JVM version as part of the same cql-to-elm KMP project.
The JVM and JS variants use the same core CQL to ELM translator logic under commonMain.
One of the main functionalities unique to the JVM is the automatic loading of ModelInfoProvider, LibrarySourceProvider, and UcumService implementations which relies on ServiceLoader and (for ModelInfoProvider and LibrarySourceProvider) works the same way as before. The JS variant requires you to register the providers explicitly when configuring the ModelManager and LibraryManager.
Kotlin code generation and multiplatform serialization
The previous version of the project used JAXB's xjc tool to generate Java classes from the ELM and ModelInfo XML schemas. The generated code was specific to the JVM and included JAXB annotations and methods for serialization and deserialization. At run time, the translator used either JAXB or Jackson to read and write ELM and ModelInfo XML and JSON, depending on which of elm-(jackson|jaxb) and model-(jackson|jaxb) were included. The translator relied on ServiceLoader to load the implementations of the ElmLibraryReaderProvider, ElmLibraryWriterProvider, and ModelInfoReaderProvider interfaces to use for this purpose.
In v4, a custom plugin is used to generate pure-Kotlin ELM and model info classes from the same XML schemas. These classes do not depend on JAXB but otherwise have the same structure as the previous Java classes. Runtime parsing and writing of XML is now handled by the custom multiplatform XML methods, while kotlinx.serialization is used for JSON. This functionality is available in the translator by default, so no peer dependencies are required.
In case you need to customize the serialization behavior for ELM, you can use the new overloads of the CqlTranslator methods and LibraryManager constructor to provide your own ElmLibraryReaderProvider and ElmLibraryWriterProvider implementations.
The new CQL compiler for JavaScript environments
The JS variant of the compiler is currently in beta, and its API may change in a backwards-incompatible way before reaching a stable release. The end goal is, however, to have the common API across the JVM and JS variants with minimal differences.
Here is a simple example of using the JS compiler to translate a CQL library to ELM:
import { ModelManager, LibraryManager, CqlTranslator } from "@cqframework/cql/cql-to-elm";
const modelManager = new ModelManager();
// Register the necessary model info providers with the model manager here
const libraryManager = new LibraryManager(modelManager);
// Register the necessary library source providers with the library manager here
const cqlTranslator = CqlTranslator.fromText("library Test version '1.0.0'", libraryManager);
const elmJson = cqlTranslator.toJson();
A more complete example, including how to set up a web app that uses the JS compiler, can be found in Src/js/cql-to-elm-ui.