package org.opencds.cqf.cql.model; import java.util.Calendar; import org.hl7.fhir.r4.model.*; import ca.uhn.fhir.context.FhirContext; import ca.uhn.fhir.context.FhirVersionEnum; public class R4FhirModelResolver extends FhirModelResolver<Base, BaseDateTimeType, TimeType, SimpleQuantity, IdType, Resource, Enumeration<?>, EnumFactory<?>> { public R4FhirModelResolver() { this(FhirContext.forR4()); } private R4FhirModelResolver(FhirContext fhirContext) { super(fhirContext); this.setPackageName("org.hl7.fhir.r4.model"); if (fhirContext.getVersion().getVersion() != FhirVersionEnum.R4) { throw new IllegalArgumentException("The supplied context is not configured for R4"); } } protected void initialize() { // HAPI has some bugs where it's missing annotations on certain types. This patches that. this.fhirContext.registerCustomType(AnnotatedUuidType.class); // The context loads Resources on demand which can cause resolution to fail in certain cases // This forces all Resource types to be loaded. for (Enumerations.ResourceType type :Enumerations.ResourceType.values()) { // These are abstract types that should never be resolved directly. switch (type) { case DOMAINRESOURCE: case RESOURCE: case NULL: continue; default: } this.fhirContext.getResourceDefinition(type.toCode()); } } @Override protected Object resolveProperty(Object target, String path) { // This is kind of a hack to get around contained resources - HAPI doesn't have ResourceContainer type for STU3 if (target instanceof Resource && ((Resource) target).fhirType().equals(path)) { return target; } return super.resolveProperty(target, path); } protected Boolean equalsDeep(Base left, Base right) { return left.equalsDeep(right); } protected SimpleQuantity castToSimpleQuantity(Base base) { return base.castToSimpleQuantity(base); } protected Calendar getCalendar(BaseDateTimeType dateTime) { return dateTime.getValueAsCalendar(); } protected Integer getCalendarConstant(BaseDateTimeType dateTime) { return dateTime.getPrecision().getCalendarConstant(); } protected String timeToString(TimeType time) { return time.getValue(); } protected String idToString(IdType id) { return id.getIdPart(); } protected String getResourceType(Resource resource) { return resource.fhirType(); } protected Enumeration<?> enumConstructor(EnumFactory<?> factory) { return new Enumeration<>(factory); } protected Boolean enumChecker(Object object) { return object instanceof Enumeration; } protected Class<?> enumFactoryTypeGetter(Enumeration<?> enumeration) { return enumeration.getEnumFactory().getClass(); } @Override public Class<?> resolveType(String typeName) { // TODO: Might be able to patch some of these by registering custom types in HAPI. switch(typeName) { case "ConfidentialityClassification": typeName = "Composition$DocumentConfidentiality"; break; case "ContractResourceStatusCodes": typeName = "Contract$ContractStatus"; break; case "EventStatus": typeName = "Procedure$ProcedureStatus"; break; case "FinancialResourceStatusCodes": typeName = "ClaimResponse$ClaimResponseStatus"; break; case "SampledDataDataType": typeName = "StringType"; break; case "ClaimProcessingCodes": typeName = "ClaimResponse$RemittanceOutcome"; break; case "vConfidentialityClassification": typeName = "Composition$DocumentConfidentiality"; break; case "ContractResourcePublicationStatusCodes": typeName = "Contract$ContractPublicationStatus"; break; } return super.resolveType(typeName); } }