diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/context/BaseRuntimeChildDatatypeDefinition.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/context/BaseRuntimeChildDatatypeDefinition.java index 3a6ac9f734e..e74dec67406 100644 --- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/context/BaseRuntimeChildDatatypeDefinition.java +++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/context/BaseRuntimeChildDatatypeDefinition.java @@ -47,14 +47,18 @@ public abstract class BaseRuntimeChildDatatypeDefinition extends BaseRuntimeDecl myDatatype = theDatatype; } + /** + * If this child has a bound type, this method will return the Enum type that + * it is bound to. Otherwise, will return null. + */ + public Class> getBoundEnumType() { + return null; + } + @Override - public String getChildNameByDatatype(Class theDatatype) { - Class nextType = theDatatype; - while (nextType.equals(Object.class) == false) { - if (myDatatype.equals(nextType)) { - return getElementName(); - } - nextType = nextType.getSuperclass(); + public BaseRuntimeElementDefinition getChildByName(String theName) { + if (getElementName().equals(theName)) { + return myElementDefinition; } return null; } @@ -72,9 +76,13 @@ public abstract class BaseRuntimeChildDatatypeDefinition extends BaseRuntimeDecl } @Override - public BaseRuntimeElementDefinition getChildByName(String theName) { - if (getElementName().equals(theName)) { - return myElementDefinition; + public String getChildNameByDatatype(Class theDatatype) { + Class nextType = theDatatype; + while (nextType.equals(Object.class) == false) { + if (myDatatype.equals(nextType)) { + return getElementName(); + } + nextType = nextType.getSuperclass(); } return null; } diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/context/ModelScanner.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/context/ModelScanner.java index f7ce6f3ff76..257e09a8751 100644 --- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/context/ModelScanner.java +++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/context/ModelScanner.java @@ -576,9 +576,10 @@ class ModelScanner { if (IPrimitiveType.class.isAssignableFrom(nextElementType)) { if (nextElementType.equals(BoundCodeDt.class)) { IValueSetEnumBinder> binder = getBoundCodeBinder(next); - def = new RuntimeChildPrimitiveBoundCodeDatatypeDefinition(next, elementName, childAnnotation, descriptionAnnotation, nextDatatype, binder); + Class> enumType = determineEnumTypeForBoundField(next); + def = new RuntimeChildPrimitiveBoundCodeDatatypeDefinition(next, elementName, childAnnotation, descriptionAnnotation, nextDatatype, binder, enumType); } else if (IBaseEnumeration.class.isAssignableFrom(nextElementType)) { - Class binderType = ReflectionUtil.getGenericCollectionTypeOfFieldWithSecondOrderForList(next); + Class> binderType = determineEnumTypeForBoundField(next); def = new RuntimeChildPrimitiveEnumerationDatatypeDefinition(next, elementName, childAnnotation, descriptionAnnotation, nextDatatype, binderType); } else { def = new RuntimeChildPrimitiveDatatypeDefinition(next, elementName, descriptionAnnotation, childAnnotation, nextDatatype); @@ -588,7 +589,8 @@ class ModelScanner { } else { if (IBoundCodeableConcept.class.isAssignableFrom(nextElementType)) { IValueSetEnumBinder> binder = getBoundCodeBinder(next); - def = new RuntimeChildCompositeBoundDatatypeDefinition(next, elementName, childAnnotation, descriptionAnnotation, nextDatatype, binder); + Class> enumType = determineEnumTypeForBoundField(next); + def = new RuntimeChildCompositeBoundDatatypeDefinition(next, elementName, childAnnotation, descriptionAnnotation, nextDatatype, binder, enumType); } else if (BaseNarrativeDt.class.isAssignableFrom(nextElementType) || INarrative.class.isAssignableFrom(nextElementType)) { def = new RuntimeChildNarrativeDefinition(next, elementName, childAnnotation, descriptionAnnotation, nextDatatype); } else { @@ -618,6 +620,12 @@ class ModelScanner { } } + private Class> determineEnumTypeForBoundField(Field next) { + @SuppressWarnings("unchecked") + Class> enumType = (Class>) ReflectionUtil.getGenericCollectionTypeOfFieldWithSecondOrderForList(next); + return enumType; + } + private String scanPrimitiveDatatype(Class> theClass, DatatypeDef theDatatypeDefinition) { ourLog.debug("Scanning resource class: {}", theClass.getName()); diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/context/RuntimeChildCompositeBoundDatatypeDefinition.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/context/RuntimeChildCompositeBoundDatatypeDefinition.java index a04fdeb2118..5894e201f1e 100644 --- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/context/RuntimeChildCompositeBoundDatatypeDefinition.java +++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/context/RuntimeChildCompositeBoundDatatypeDefinition.java @@ -22,6 +22,7 @@ package ca.uhn.fhir.context; import java.lang.reflect.Field; +import org.apache.commons.lang3.Validate; import org.hl7.fhir.instance.model.api.IBase; import ca.uhn.fhir.model.api.IValueSetEnumBinder; @@ -31,13 +32,15 @@ import ca.uhn.fhir.model.api.annotation.Description; public class RuntimeChildCompositeBoundDatatypeDefinition extends RuntimeChildCompositeDatatypeDefinition { private IValueSetEnumBinder> myBinder; + private Class> myEnumType; - public RuntimeChildCompositeBoundDatatypeDefinition(Field theField, String theElementName, Child theChildAnnotation, Description theDescriptionAnnotation, Class theDatatype, IValueSetEnumBinder> theBinder) { + public RuntimeChildCompositeBoundDatatypeDefinition(Field theField, String theElementName, Child theChildAnnotation, Description theDescriptionAnnotation, Class theDatatype, IValueSetEnumBinder> theBinder, Class> theEnumType) { super(theField, theElementName, theChildAnnotation, theDescriptionAnnotation, theDatatype); + Validate.notNull(theBinder, "theBinder must not be null"); + Validate.notNull(theEnumType, "theEnumType must not be null"); + myBinder = theBinder; - if (theBinder==null) { - throw new IllegalArgumentException("Binder must not be null"); - } + myEnumType = theEnumType; } @Override @@ -45,4 +48,9 @@ public class RuntimeChildCompositeBoundDatatypeDefinition extends RuntimeChildCo return myBinder; } + @Override + public Class> getBoundEnumType() { + return myEnumType; + } + } diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/context/RuntimeChildPrimitiveBoundCodeDatatypeDefinition.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/context/RuntimeChildPrimitiveBoundCodeDatatypeDefinition.java index 2d419f4078d..8fc45a8a130 100644 --- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/context/RuntimeChildPrimitiveBoundCodeDatatypeDefinition.java +++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/context/RuntimeChildPrimitiveBoundCodeDatatypeDefinition.java @@ -30,11 +30,18 @@ import ca.uhn.fhir.model.api.annotation.Description; public class RuntimeChildPrimitiveBoundCodeDatatypeDefinition extends RuntimeChildPrimitiveDatatypeDefinition { private Object myBinder; + private Class> myEnumType; - public RuntimeChildPrimitiveBoundCodeDatatypeDefinition(Field theField, String theElementName, Child theChildAnnotation, Description theDescriptionAnnotation, Class theDatatype, Object theBinder) { + public RuntimeChildPrimitiveBoundCodeDatatypeDefinition(Field theField, String theElementName, Child theChildAnnotation, Description theDescriptionAnnotation, Class theDatatype, Object theBinder, Class> theEnumType) { super(theField, theElementName, theDescriptionAnnotation, theChildAnnotation, theDatatype); myBinder = theBinder; + myEnumType = theEnumType; + } + + @Override + public Class> getBoundEnumType() { + return myEnumType; } @Override diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/context/RuntimeChildPrimitiveEnumerationDatatypeDefinition.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/context/RuntimeChildPrimitiveEnumerationDatatypeDefinition.java index ae4c5513d3c..c3f1e7f0d49 100644 --- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/context/RuntimeChildPrimitiveEnumerationDatatypeDefinition.java +++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/context/RuntimeChildPrimitiveEnumerationDatatypeDefinition.java @@ -30,19 +30,24 @@ import ca.uhn.fhir.model.api.annotation.Description; public class RuntimeChildPrimitiveEnumerationDatatypeDefinition extends RuntimeChildPrimitiveDatatypeDefinition { private Object myBinder; - private Class myEnumerationType; + private Class> myEnumType; - public RuntimeChildPrimitiveEnumerationDatatypeDefinition(Field theField, String theElementName, Child theChildAnnotation, Description theDescriptionAnnotation, Class theDatatype, Class theBinderType) { + public RuntimeChildPrimitiveEnumerationDatatypeDefinition(Field theField, String theElementName, Child theChildAnnotation, Description theDescriptionAnnotation, Class theDatatype, Class> theBinderType) { super(theField, theElementName, theDescriptionAnnotation, theChildAnnotation, theDatatype); - myEnumerationType = theBinderType; + myEnumType = theBinderType; + } + + @Override + public Class> getBoundEnumType() { + return myEnumType; } @Override public Object getInstanceConstructorArguments() { Object retVal = myBinder; if (retVal == null) { - retVal = toEnumFactory(myEnumerationType); + retVal = toEnumFactory(myEnumType); myBinder = retVal; } return retVal; diff --git a/hapi-fhir-structures-dstu2/src/test/java/ca/uhn/fhir/ctx/FhirContextDstu2Test.java b/hapi-fhir-structures-dstu2/src/test/java/ca/uhn/fhir/ctx/FhirContextDstu2Test.java new file mode 100644 index 00000000000..4013913883e --- /dev/null +++ b/hapi-fhir-structures-dstu2/src/test/java/ca/uhn/fhir/ctx/FhirContextDstu2Test.java @@ -0,0 +1,39 @@ +package ca.uhn.fhir.ctx; + +import static org.junit.Assert.assertEquals; + +import org.junit.Test; + +import ca.uhn.fhir.context.BaseRuntimeChildDatatypeDefinition; +import ca.uhn.fhir.context.FhirContext; +import ca.uhn.fhir.context.RuntimeResourceDefinition; +import ca.uhn.fhir.model.dstu2.resource.Patient; +import ca.uhn.fhir.model.dstu2.valueset.AdministrativeGenderEnum; +import ca.uhn.fhir.model.dstu2.valueset.MaritalStatusCodesEnum; + +public class FhirContextDstu2Test { + private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(FhirContextDstu2Test.class); + + private FhirContext ourCtx = FhirContext.forDstu2(); + + @Test + public void testQueryBoundCode() { + RuntimeResourceDefinition patientType = ourCtx.getResourceDefinition(Patient.class); + String childName = "gender"; + BaseRuntimeChildDatatypeDefinition genderChild = (BaseRuntimeChildDatatypeDefinition) patientType.getChildByName(childName); + ourLog.trace(genderChild.getClass().getName()); + + assertEquals(AdministrativeGenderEnum.class, genderChild.getBoundEnumType()); + } + + @Test + public void testQueryBoundCodeableConcept() { + RuntimeResourceDefinition patientType = ourCtx.getResourceDefinition(Patient.class); + String childName = "maritalStatus"; + BaseRuntimeChildDatatypeDefinition genderChild = (BaseRuntimeChildDatatypeDefinition) patientType.getChildByName(childName); + ourLog.trace(genderChild.getClass().getName()); + + assertEquals(MaritalStatusCodesEnum.class, genderChild.getBoundEnumType()); + } + +} diff --git a/hapi-fhir-structures-dstu3/src/main/java/org/hl7/fhir/dstu3/hapi/ctx/FhirContextDstu3Test.java b/hapi-fhir-structures-dstu3/src/main/java/org/hl7/fhir/dstu3/hapi/ctx/FhirContextDstu3Test.java new file mode 100644 index 00000000000..0d7ed35c675 --- /dev/null +++ b/hapi-fhir-structures-dstu3/src/main/java/org/hl7/fhir/dstu3/hapi/ctx/FhirContextDstu3Test.java @@ -0,0 +1,29 @@ +package org.hl7.fhir.dstu3.hapi.ctx; + +import static org.junit.Assert.assertEquals; + +import org.hl7.fhir.dstu3.model.Enumerations.AdministrativeGender; +import org.hl7.fhir.dstu3.model.Patient; +import org.junit.Test; + +import ca.uhn.fhir.context.BaseRuntimeChildDatatypeDefinition; +import ca.uhn.fhir.context.FhirContext; +import ca.uhn.fhir.context.RuntimeResourceDefinition; + +public class FhirContextDstu3Test { + private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(FhirContextDstu3Test.class); + + private FhirContext ourCtx = FhirContext.forDstu3(); + + @Test + public void testQueryBoundCode() { + RuntimeResourceDefinition patientType = ourCtx.getResourceDefinition(Patient.class); + String childName = "gender"; + BaseRuntimeChildDatatypeDefinition genderChild = (BaseRuntimeChildDatatypeDefinition) patientType.getChildByName(childName); + ourLog.trace(genderChild.getClass().getName()); + + assertEquals(AdministrativeGender.class, genderChild.getBoundEnumType()); + } + + +}