Extensions working now

This commit is contained in:
jamesagnew 2014-02-23 18:13:59 -05:00
parent 20a705929c
commit 44f6e804b1
37 changed files with 941 additions and 382 deletions

View File

@ -49,17 +49,16 @@
<attribute value="jar:file:/Users/james/.m2/repository/org/slf4j/slf4j-api/1.7.6/slf4j-api-1.7.6-javadoc.jar!/" name="javadoc_location"/>
</attributes>
</classpathentry>
<classpathentry kind="var" path="M2_REPO/stax/stax-api/1.0.1/stax-api-1.0.1.jar"/>
<classpathentry kind="var" path="M2_REPO/org/codehaus/woodstox/stax2-api/3.1.1/stax2-api-3.1.1.jar" sourcepath="M2_REPO/org/codehaus/woodstox/stax2-api/3.1.1/stax2-api-3.1.1-sources.jar"/>
<classpathentry kind="var" path="M2_REPO/com/fasterxml/staxmate/staxmate/2.2.0/staxmate-2.2.0.jar" sourcepath="M2_REPO/com/fasterxml/staxmate/staxmate/2.2.0/staxmate-2.2.0-sources.jar">
<attributes>
<attribute value="jar:file:/Users/james/.m2/repository/com/fasterxml/staxmate/staxmate/2.2.0/staxmate-2.2.0-javadoc.jar!/" name="javadoc_location"/>
</attributes>
</classpathentry>
<classpathentry kind="var" path="M2_REPO/org/codehaus/woodstox/woodstox-core-asl/4.2.0/woodstox-core-asl-4.2.0.jar" sourcepath="M2_REPO/org/codehaus/woodstox/woodstox-core-asl/4.2.0/woodstox-core-asl-4.2.0-sources.jar">
<attributes>
<attribute value="jar:file:/Users/james/.m2/repository/org/codehaus/woodstox/woodstox-core-asl/4.2.0/woodstox-core-asl-4.2.0-javadoc.jar!/" name="javadoc_location"/>
</attributes>
</classpathentry>
<classpathentry kind="var" path="M2_REPO/xmlunit/xmlunit/1.5/xmlunit-1.5.jar" sourcepath="M2_REPO/xmlunit/xmlunit/1.5/xmlunit-1.5-sources.jar">
<attributes>
<attribute value="jar:file:/Users/james/.m2/repository/xmlunit/xmlunit/1.5/xmlunit-1.5-javadoc.jar!/" name="javadoc_location"/>
</attributes>
</classpathentry>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.6"/>
</classpath>

View File

@ -29,14 +29,8 @@
<artifactId>woodstox-core-asl</artifactId>
<version>4.2.0</version>
</dependency>
<!--
<dependency>
<groupId>org.codehaus.woodstox</groupId>
<artifactId>stax2-api</artifactId>
<version>3.1.3</version>
</dependency>
-->
<!-- <dependency> <groupId>org.codehaus.woodstox</groupId> <artifactId>stax2-api</artifactId> <version>3.1.3</version> </dependency> -->
<!-- General -->
<dependency>
@ -76,7 +70,12 @@
<version>1.3.2</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>xmlunit</groupId>
<artifactId>xmlunit</artifactId>
<version>1.5</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>

View File

@ -9,7 +9,7 @@ import ca.uhn.fhir.model.api.ICodeEnum;
import ca.uhn.fhir.model.api.IDatatype;
import ca.uhn.fhir.model.api.IElement;
public abstract class BaseRuntimeChildDatatypeDefinition extends BaseRuntimeUndeclaredChildDefinition {
public abstract class BaseRuntimeChildDatatypeDefinition extends BaseRuntimeDeclaredChildDefinition {
private Class<? extends ICodeEnum> myCodeType;
private Class<? extends IDatatype> myDatatype;

View File

@ -29,4 +29,12 @@ public abstract class BaseRuntimeChildDefinition {
public interface IMutator {
void addValue(Object theTarget, IElement theValue);
}
public String getExtensionUrl() {
return null;
}
// public String getExtensionUrl() {
// return null;
// }
}

View File

@ -12,7 +12,7 @@ import java.util.List;
import ca.uhn.fhir.model.api.IElement;
import ca.uhn.fhir.util.BeanUtils;
public abstract class BaseRuntimeUndeclaredChildDefinition extends BaseRuntimeChildDefinition {
public abstract class BaseRuntimeDeclaredChildDefinition extends BaseRuntimeChildDefinition {
private final IAccessor myAccessor;
private final String myElementName;
@ -21,7 +21,7 @@ public abstract class BaseRuntimeUndeclaredChildDefinition extends BaseRuntimeCh
private final int myMin;
private final IMutator myMutator;
BaseRuntimeUndeclaredChildDefinition(Field theField, int theMin, int theMax, String theElementName) throws ConfigurationException {
BaseRuntimeDeclaredChildDefinition(Field theField, int theMin, int theMax, String theElementName) throws ConfigurationException {
super();
if (theField == null) {
throw new IllegalArgumentException("No field speficied");

View File

@ -13,16 +13,36 @@ import ca.uhn.fhir.parser.DataFormatException;
public abstract class BaseRuntimeElementCompositeDefinition<T extends ICompositeElement> extends BaseRuntimeElementDefinition<T> {
private List<BaseRuntimeChildDefinition> myChildren = new ArrayList<BaseRuntimeChildDefinition>();
private List<RuntimeChildDeclaredExtensionDefinition> myExtensions = new ArrayList<RuntimeChildDeclaredExtensionDefinition>();
private Map<String, BaseRuntimeChildDefinition> myNameToChild = new HashMap<String, BaseRuntimeChildDefinition>();
private Map<String, RuntimeChildDeclaredExtensionDefinition> myUrlToExtension = new HashMap<String, RuntimeChildDeclaredExtensionDefinition>();
public BaseRuntimeElementCompositeDefinition(String theName, Class<? extends T> theImplementingClass) {
super(theName, theImplementingClass);
}
public void addChild(BaseRuntimeChildDefinition theNext) {
if (theNext == null) {
throw new NullPointerException();
}
if (theNext.getExtensionUrl() != null) {
throw new IllegalArgumentException("Shouldn't haven an extension URL, use addExtension instead");
}
myChildren.add(theNext);
}
public void addExtension(RuntimeChildDeclaredExtensionDefinition theExtension) {
if (theExtension== null) {
throw new NullPointerException();
}
myExtensions.add(theExtension);
}
public List<RuntimeChildDeclaredExtensionDefinition> getExtensions() {
return myExtensions;
}
public BaseRuntimeChildDefinition getChildByNameOrThrowDataFormatException(String theName) throws DataFormatException {
BaseRuntimeChildDefinition retVal = myNameToChild.get(theName);
if (retVal == null) {
@ -31,12 +51,25 @@ public abstract class BaseRuntimeElementCompositeDefinition<T extends IComposite
return retVal;
}
public List<BaseRuntimeChildDefinition> getChildren() {
return myChildren;
}
/**
* Returns null if none
*/
public RuntimeChildDeclaredExtensionDefinition getDeclaredExtension(String theExtensionUrl) {
return myUrlToExtension.get(theExtensionUrl);
}
@Override
public
void sealAndInitialize(Map<Class<? extends IElement>, BaseRuntimeElementDefinition<?>> theClassToElementDefinitions) {
public void sealAndInitialize(Map<Class<? extends IElement>, BaseRuntimeElementDefinition<?>> theClassToElementDefinitions) {
for (BaseRuntimeChildDefinition next : myChildren) {
next.sealAndInitialize(theClassToElementDefinitions);
}
for (BaseRuntimeChildDefinition next : myExtensions) {
next.sealAndInitialize(theClassToElementDefinitions);
}
myNameToChild = new HashMap<String, BaseRuntimeChildDefinition>();
for (BaseRuntimeChildDefinition next : myChildren) {
@ -48,12 +81,18 @@ public abstract class BaseRuntimeElementCompositeDefinition<T extends IComposite
}
}
}
for (RuntimeChildDeclaredExtensionDefinition next : myExtensions) {
String extUrl = next.getExtensionUrl();
if (myUrlToExtension.containsKey(extUrl)) {
throw new ConfigurationException("Duplicate extension URL: " + extUrl);
} else {
myUrlToExtension.put(extUrl, next);
}
}
myChildren = Collections.unmodifiableList(myChildren);
myNameToChild = Collections.unmodifiableMap(myNameToChild);
}
public List<BaseRuntimeChildDefinition> getChildren() {
return myChildren;
myExtensions = Collections.unmodifiableList(myExtensions);
}
}

View File

@ -49,7 +49,7 @@ public abstract class BaseRuntimeElementDefinition<T extends IElement> {
public abstract ChildTypeEnum getChildType();
public enum ChildTypeEnum {
COMPOSITE_DATATYPE, PRIMITIVE_DATATYPE, RESOURCE, RESOURCE_REF, RESOURCE_BLOCK, PRIMITIVE_XHTML, UNDECL_EXT
COMPOSITE_DATATYPE, PRIMITIVE_DATATYPE, RESOURCE, RESOURCE_REF, RESOURCE_BLOCK, PRIMITIVE_XHTML, UNDECL_EXT, EXTENSION_DECLARED
}

View File

@ -15,6 +15,7 @@ import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
import java.util.TreeSet;
import ca.uhn.fhir.model.api.CodeableConceptElement;
import ca.uhn.fhir.model.api.ICodeEnum;
@ -32,6 +33,7 @@ import ca.uhn.fhir.model.api.annotation.ChildResource;
import ca.uhn.fhir.model.api.annotation.Choice;
import ca.uhn.fhir.model.api.annotation.CodeTableDef;
import ca.uhn.fhir.model.api.annotation.DatatypeDef;
import ca.uhn.fhir.model.api.annotation.Extension;
import ca.uhn.fhir.model.api.annotation.Narrative;
import ca.uhn.fhir.model.api.annotation.ResourceDef;
import ca.uhn.fhir.model.datatype.CodeDt;
@ -44,7 +46,6 @@ class ModelScanner {
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(ModelScanner.class);
private Map<Class<? extends IElement>, BaseRuntimeElementDefinition<?>> myClassToElementDefinitions = new HashMap<Class<? extends IElement>, BaseRuntimeElementDefinition<?>>();
private Map<String, BaseRuntimeElementDefinition<?>> myDatatypeAttributeNameToDefinition = new HashMap<String, BaseRuntimeElementDefinition<?>>();
private Map<String, RuntimeResourceDefinition> myNameToResourceDefinitions = new HashMap<String, RuntimeResourceDefinition>();
private Set<Class<? extends IElement>> myScanAlso = new HashSet<Class<? extends IElement>>();
@ -81,7 +82,8 @@ class ModelScanner {
next.sealAndInitialize(myClassToElementDefinitions);
}
myRuntimeChildUndeclaredExtensionDefinition = new RuntimeChildUndeclaredExtensionDefinition(myDatatypeAttributeNameToDefinition);
myRuntimeChildUndeclaredExtensionDefinition = new RuntimeChildUndeclaredExtensionDefinition();
myRuntimeChildUndeclaredExtensionDefinition.sealAndInitialize(myClassToElementDefinitions);
ourLog.info("Done scanning FHIR library, found {} model entries", myClassToElementDefinitions.size());
@ -99,12 +101,6 @@ class ModelScanner {
return (myNameToResourceDefinitions);
}
private void addDatatype(BaseRuntimeElementDefinition<?> theResourceDef) {
String attrName = theResourceDef.getName();
attrName = "value" + attrName.substring(0, 1).toUpperCase() + attrName.substring(1);
myDatatypeAttributeNameToDefinition.put(attrName, theResourceDef);
}
private void addScanAlso(Class<? extends IElement> theType) {
if (theType.isInterface()) {
return;
@ -112,10 +108,6 @@ class ModelScanner {
myScanAlso.add(theType);
}
public Map<String, BaseRuntimeElementDefinition<?>> getDatatypeAttributeNameToDefinition() {
return myDatatypeAttributeNameToDefinition;
}
private void scan(Class<? extends IElement> theClass) throws ConfigurationException {
BaseRuntimeElementDefinition<?> existingDef = myClassToElementDefinitions.get(theClass);
if (existingDef != null) {
@ -174,6 +166,7 @@ class ModelScanner {
}
}
private void scanBlock(Class<? extends IResourceBlock> theClass, Block theBlockDefinition) {
ourLog.debug("Scanning resource block class: {}", theClass.getName());
@ -202,15 +195,14 @@ class ModelScanner {
RuntimeCompositeDatatypeDefinition resourceDef = new RuntimeCompositeDatatypeDefinition(resourceName, theClass);
myClassToElementDefinitions.put(theClass, resourceDef);
addDatatype(resourceDef);
scanCompositeElementForChildren(theClass, resourceDef, null);
}
@SuppressWarnings("unchecked")
private void scanCompositeElementForChildren(Class<? extends ICompositeElement> theClass, BaseRuntimeElementCompositeDefinition<?> theDefinition, Integer theIdentifierOrder) {
Set<String> elementNames = new HashSet<String>();
TreeMap<Integer, BaseRuntimeUndeclaredChildDefinition> orderToElementDef = new TreeMap<Integer, BaseRuntimeUndeclaredChildDefinition>();
TreeMap<Integer, BaseRuntimeDeclaredChildDefinition> orderToElementDef = new TreeMap<Integer, BaseRuntimeDeclaredChildDefinition>();
TreeMap<Integer, BaseRuntimeDeclaredChildDefinition> orderToExtensionDef = new TreeMap<Integer, BaseRuntimeDeclaredChildDefinition>();
LinkedList<Class<? extends ICompositeElement>> classes = new LinkedList<Class<? extends ICompositeElement>>();
Class<? extends ICompositeElement> current = theClass;
@ -224,11 +216,11 @@ class ModelScanner {
} while (current != null);
for (Class<? extends ICompositeElement> next : classes) {
scanCompositeElementForChildren(next, theDefinition, elementNames, orderToElementDef);
scanCompositeElementForChildren(next, theDefinition, elementNames, orderToElementDef, orderToExtensionDef);
}
while (orderToElementDef.size() > 0 && orderToElementDef.firstKey() < 0) {
BaseRuntimeUndeclaredChildDefinition elementDef = orderToElementDef.remove(orderToElementDef.firstKey());
BaseRuntimeDeclaredChildDefinition elementDef = orderToElementDef.remove(orderToElementDef.firstKey());
if (elementDef.getElementName().equals("identifier")) {
orderToElementDef.put(theIdentifierOrder, elementDef);
} else {
@ -236,18 +228,25 @@ class ModelScanner {
}
}
for (int i = 0; i < orderToElementDef.size(); i++) {
if (!orderToElementDef.containsKey(i)) {
throw new ConfigurationException("Type '" + theClass.getCanonicalName() + "' does not have a child with order " + i + " (in other words, there are gaps between specified child orders)");
TreeSet<Integer> orders = new TreeSet<Integer>();
orders.addAll(orderToElementDef.keySet());
orders.addAll(orderToExtensionDef.keySet());
for (Integer i : orders) {
BaseRuntimeChildDefinition nextChild = orderToElementDef.get(i);
if (nextChild != null) {
theDefinition.addChild(nextChild);
}
BaseRuntimeDeclaredChildDefinition nextExt = orderToExtensionDef.get(i);
if (nextExt != null) {
theDefinition.addExtension((RuntimeChildDeclaredExtensionDefinition)nextExt);
}
BaseRuntimeChildDefinition next = orderToElementDef.get(i);
theDefinition.addChild(next);
}
}
@SuppressWarnings("unchecked")
private void scanCompositeElementForChildren(Class<? extends ICompositeElement> theClass, BaseRuntimeElementCompositeDefinition<?> theDefinition, Set<String> elementNames, TreeMap<Integer, BaseRuntimeUndeclaredChildDefinition> orderToElementDef) {
private void scanCompositeElementForChildren(Class<? extends ICompositeElement> theClass, BaseRuntimeElementCompositeDefinition<?> theDefinition, Set<String> elementNames, TreeMap<Integer, BaseRuntimeDeclaredChildDefinition> theOrderToElementDef, TreeMap<Integer,BaseRuntimeDeclaredChildDefinition> theOrderToExtensionDef) {
for (Field next : theClass.getDeclaredFields()) {
Narrative hasNarrative = next.getAnnotation(Narrative.class);
@ -272,13 +271,19 @@ class ModelScanner {
int order = element.order();
int min = element.min();
int max = element.max();
TreeMap<Integer, BaseRuntimeDeclaredChildDefinition> orderMap = theOrderToElementDef;
Extension extensionAttr = next.getAnnotation(Extension.class);
if (extensionAttr != null) {
orderMap = theOrderToExtensionDef;
}
/*
* Anything that's marked as unknown is given a new ID that is <0 so
* that it doesn't conflict wityh any given IDs and can be figured
* out later
*/
while (order == Child.ORDER_UNKNOWN && orderToElementDef.containsKey(order)) {
while (order == Child.ORDER_UNKNOWN && orderMap.containsKey(order)) {
order--;
}
@ -288,20 +293,15 @@ class ModelScanner {
choiceTypes.add(nextChoiceType);
}
if (orderToElementDef.containsKey(order)) {
throw new ConfigurationException("Detected duplicate field order '" + order + "' in type '" + theClass.getCanonicalName() + "'");
if (orderMap.containsKey(order)) {
throw new ConfigurationException("Detected duplicate field order '" + order + "' for element named '" + elementName + "' in type '" + theClass.getCanonicalName() + "'");
}
if (elementNames.contains(elementName)) {
throw new ConfigurationException("Detected duplicate field name '" + elementName + "' in type '" + theClass.getCanonicalName() + "'");
}
Class<?> nextElementType = next.getType();
if (List.class.equals(nextElementType)) {
nextElementType = getGenericCollectionTypeOfField(next);
} else if (Collection.class.isAssignableFrom(nextElementType)) {
throw new ConfigurationException("Field '" + elementName + "' in type '" + theClass.getCanonicalName() + "' is a Collection - Only java.util.List curently supported");
}
Class<?> nextElementType = determineElementType(next);
ChildResource resRefAnnotation = next.getAnnotation(ChildResource.class);
if (choiceTypes.isEmpty() == false) {
@ -312,8 +312,18 @@ class ModelScanner {
addScanAlso(nextType);
}
RuntimeChildChoiceDefinition def = new RuntimeChildChoiceDefinition(next, elementName, min, max, choiceTypes);
orderToElementDef.put(order, def);
orderMap.put(order, def);
} else if (extensionAttr != null) {
/*
* Child is an extension
*/
Class<? extends IElement> et = (Class<? extends IElement>) nextElementType;
RuntimeChildDeclaredExtensionDefinition def = new RuntimeChildDeclaredExtensionDefinition(next, min, max, elementName, extensionAttr.url(), et);
orderMap.put(order, def);
if (IElement.class.isAssignableFrom(nextElementType )) {
addScanAlso((Class<? extends IElement>) nextElementType);
}
} else if (ResourceReference.class.isAssignableFrom(nextElementType)) {
/*
* Child is a resource reference
@ -328,7 +338,7 @@ class ModelScanner {
addScanAlso(nextType);
}
RuntimeChildResourceDefinition def = new RuntimeChildResourceDefinition(next, elementName, min, max, refTypesList);
orderToElementDef.put(order, def);
orderMap.put(order, def);
} else if (IResourceBlock.class.isAssignableFrom(nextElementType)) {
/*
@ -339,7 +349,7 @@ class ModelScanner {
Class<? extends IResourceBlock> blockDef = (Class<? extends IResourceBlock>) nextElementType;
addScanAlso(blockDef);
RuntimeChildResourceBlockDefinition def = new RuntimeChildResourceBlockDefinition(next, min, max, elementName, blockDef);
orderToElementDef.put(order, def);
orderMap.put(order, def);
} else if (IDatatype.class.isAssignableFrom(nextElementType)) {
Class<? extends IDatatype> nextDatatype = (Class<? extends IDatatype>) nextElementType;
@ -363,7 +373,7 @@ class ModelScanner {
}
}
orderToElementDef.put(order, def);
orderMap.put(order, def);
// TODO: handle codes
} else {
@ -374,6 +384,16 @@ class ModelScanner {
}
}
private Class<?> determineElementType(Field next) {
Class<?> nextElementType = next.getType();
if (List.class.equals(nextElementType)) {
nextElementType = getGenericCollectionTypeOfField(next);
} else if (Collection.class.isAssignableFrom(nextElementType)) {
throw new ConfigurationException("Field '" + next.getName() + "' in type '" + next.getClass().getCanonicalName() + "' is a Collection - Only java.util.List curently supported");
}
return nextElementType;
}
private String scanPrimitiveDatatype(Class<? extends IPrimitiveDatatype<?>> theClass, DatatypeDef theDatatypeDefinition) {
ourLog.debug("Scanning resource class: {}", theClass.getName());
@ -391,7 +411,6 @@ class ModelScanner {
resourceDef = new RuntimePrimitiveDatatypeDefinition(resourceName, theClass);
}
myClassToElementDefinitions.put(theClass, resourceDef);
addDatatype(resourceDef);
return resourceName;
}

View File

@ -10,7 +10,7 @@ import java.util.Set;
import ca.uhn.fhir.model.api.IDatatype;
import ca.uhn.fhir.model.api.IElement;
public class RuntimeChildChoiceDefinition extends BaseRuntimeUndeclaredChildDefinition {
public class RuntimeChildChoiceDefinition extends BaseRuntimeDeclaredChildDefinition {
private List<Class<? extends IElement>> myChoiceTypes;
private Map<String, BaseRuntimeElementDefinition<?>> myNameToChildDefinition;

View File

@ -0,0 +1,101 @@
package ca.uhn.fhir.context;
import static org.apache.commons.lang3.StringUtils.*;
import java.lang.reflect.Field;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import ca.uhn.fhir.model.api.IElement;
public class RuntimeChildDeclaredExtensionDefinition extends BaseRuntimeDeclaredChildDefinition {
private Class<? extends IElement> myChildType;
private BaseRuntimeElementDefinition<?> myChildDef;
private String myDatatypeChildName;
private String myExtensionUrl;
private Map<String, RuntimeChildDeclaredExtensionDefinition> myUrlToChildExtension;
RuntimeChildDeclaredExtensionDefinition(Field theField, int theMin, int theMax, String theElementName, String theExtensionUrl, Class<? extends IElement> theChildType) throws ConfigurationException {
super(theField, theMin, theMax, theElementName);
assert isNotBlank(theExtensionUrl);
myExtensionUrl = theExtensionUrl;
myChildType = theChildType;
}
@Override
public BaseRuntimeElementDefinition<?> getChildByName(String theName) {
if (myDatatypeChildName != null) {
if (myDatatypeChildName.equals(theName)) {
return myChildDef;
}else {
return null;
}
}else {
return null;
}
}
public IElement newInstance(){
try {
return myChildType.newInstance();
} catch (InstantiationException e) {
throw new ConfigurationException("Failed to instantiate type:"+myChildType.getName(), e);
} catch (IllegalAccessException e) {
throw new ConfigurationException("Failed to instantiate type:"+myChildType.getName(), e);
}
}
@Override
public BaseRuntimeElementDefinition<?> getChildElementDefinitionByDatatype(Class<? extends IElement> theType) {
if (myChildType.equals(theType)) {
return myChildDef;
}
return null;
}
public RuntimeChildDeclaredExtensionDefinition getChildExtensionForUrl(String theUrl) {
return myUrlToChildExtension.get(theUrl);
}
@Override
public String getChildNameByDatatype(Class<? extends IElement> theDatatype) {
if (myChildType.equals(theDatatype) && myDatatypeChildName != null) {
return myDatatypeChildName;
}else {
return "extension";
}
}
public String getExtensionUrl() {
return myExtensionUrl;
}
@Override
public Set<String> getValidChildNames() {
return Collections.emptySet();
}
@Override
void sealAndInitialize(Map<Class<? extends IElement>, BaseRuntimeElementDefinition<?>> theClassToElementDefinitions) {
myUrlToChildExtension = new HashMap<String, RuntimeChildDeclaredExtensionDefinition>();
BaseRuntimeElementDefinition<?> elementDef = theClassToElementDefinitions.get(myChildType);
if (elementDef instanceof RuntimePrimitiveDatatypeDefinition || elementDef instanceof RuntimeCompositeDatatypeDefinition) {
myDatatypeChildName = "value" + elementDef.getName().substring(0, 1).toUpperCase() + elementDef.getName().substring(1);
myChildDef = elementDef;
} else {
RuntimeResourceBlockDefinition extDef = ((RuntimeResourceBlockDefinition)elementDef);
for (RuntimeChildDeclaredExtensionDefinition next : extDef.getExtensions()) {
myUrlToChildExtension.put(next.getExtensionUrl(), next);
}
myChildDef = extDef;
}
myUrlToChildExtension = Collections.unmodifiableMap(myUrlToChildExtension);
}
}

View File

@ -9,7 +9,7 @@ import ca.uhn.fhir.model.api.IDatatype;
import ca.uhn.fhir.model.api.IElement;
import ca.uhn.fhir.model.api.IResourceBlock;
public class RuntimeChildResourceBlockDefinition extends BaseRuntimeUndeclaredChildDefinition {
public class RuntimeChildResourceBlockDefinition extends BaseRuntimeDeclaredChildDefinition {
private RuntimeResourceBlockDefinition myElementDef;
private Class<? extends IResourceBlock> myResourceBlockType;

View File

@ -11,7 +11,7 @@ import ca.uhn.fhir.model.api.IElement;
import ca.uhn.fhir.model.api.IResource;
import ca.uhn.fhir.model.api.ResourceReference;
public class RuntimeChildResourceDefinition extends BaseRuntimeUndeclaredChildDefinition {
public class RuntimeChildResourceDefinition extends BaseRuntimeDeclaredChildDefinition {
private BaseRuntimeElementDefinition<?> myRuntimeDef;
private List<Class<? extends IResource>> myResourceTypes;

View File

@ -19,25 +19,8 @@ public class RuntimeChildUndeclaredExtensionDefinition extends BaseRuntimeChildD
private Map<Class<? extends IElement>,String> myDatatypeToAttributeName;
private Map<Class<? extends IElement>,BaseRuntimeElementDefinition<?>> myDatatypeToDefinition;
public RuntimeChildUndeclaredExtensionDefinition(Map<String, BaseRuntimeElementDefinition<?>> theDatatypeAttributeNameToDefinition) {
myAttributeNameToDefinition=theDatatypeAttributeNameToDefinition;
myDatatypeToAttributeName = new HashMap<Class<? extends IElement>, String>();
myDatatypeToDefinition = new HashMap<Class<? extends IElement>, BaseRuntimeElementDefinition<?>>();
for (Entry<String, BaseRuntimeElementDefinition<?>> next : myAttributeNameToDefinition.entrySet()) {
@SuppressWarnings("unchecked")
Class<? extends IDatatype> type = (Class<? extends IDatatype>) next.getValue().getImplementingClass();
myDatatypeToAttributeName.put(type, next.getKey());
myDatatypeToDefinition.put(type, next.getValue());
}
// Resource Reference
myDatatypeToAttributeName.put(ResourceReference.class, "valueReference");
RuntimeResourceReferenceDefinition def = new RuntimeResourceReferenceDefinition("valueResource");
myAttributeNameToDefinition.put("valueResource", def);
myDatatypeToDefinition.put(ResourceReference.class, def);
public RuntimeChildUndeclaredExtensionDefinition() {
// nothing
}
@ -63,7 +46,32 @@ public class RuntimeChildUndeclaredExtensionDefinition extends BaseRuntimeChildD
@Override
void sealAndInitialize(Map<Class<? extends IElement>, BaseRuntimeElementDefinition<?>> theClassToElementDefinitions) {
// nothing
Map<String, BaseRuntimeElementDefinition<?>> datatypeAttributeNameToDefinition=new HashMap<String, BaseRuntimeElementDefinition<?>>();
for (BaseRuntimeElementDefinition<?> next : theClassToElementDefinitions.values()) {
if (next instanceof RuntimePrimitiveDatatypeDefinition || next instanceof RuntimeCompositeDatatypeDefinition) {
String attrName = "value" + next.getName().substring(0, 1).toUpperCase() + next.getName().substring(1);
datatypeAttributeNameToDefinition.put(attrName, next);
}
}
myAttributeNameToDefinition=datatypeAttributeNameToDefinition;
myDatatypeToAttributeName = new HashMap<Class<? extends IElement>, String>();
myDatatypeToDefinition = new HashMap<Class<? extends IElement>, BaseRuntimeElementDefinition<?>>();
for (Entry<String, BaseRuntimeElementDefinition<?>> next : myAttributeNameToDefinition.entrySet()) {
@SuppressWarnings("unchecked")
Class<? extends IDatatype> type = (Class<? extends IDatatype>) next.getValue().getImplementingClass();
myDatatypeToAttributeName.put(type, next.getKey());
myDatatypeToDefinition.put(type, next.getValue());
}
// Resource Reference
myDatatypeToAttributeName.put(ResourceReference.class, "valueReference");
RuntimeResourceReferenceDefinition def = new RuntimeResourceReferenceDefinition("valueResource");
myAttributeNameToDefinition.put("valueResource", def);
myDatatypeToDefinition.put(ResourceReference.class, def);
}
@ -95,4 +103,5 @@ public class RuntimeChildUndeclaredExtensionDefinition extends BaseRuntimeChildD
}};
}
}

View File

@ -1,5 +1,5 @@
package ca.uhn.fhir.model.api;
public interface IExtension extends IElement {
public interface IExtension extends IResourceBlock {
// nothing
}

View File

@ -5,6 +5,8 @@ import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import ca.uhn.fhir.model.api.IElement;
@Retention(RetentionPolicy.RUNTIME)
@Target(value= {ElementType.FIELD})
public @interface Child {
@ -30,4 +32,16 @@ public @interface Child {
Choice choice() default @Choice();
Class<? extends IElement> type() default NoDatatype.class;
/**
* Indicator that the type attribute is not set
*/
public class NoDatatype implements IElement
{
private NoDatatype() {
// non instantiable
}
}
}

View File

@ -1,22 +1,16 @@
package ca.uhn.fhir.model.api.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import ca.uhn.fhir.model.api.IDatatype;
import ca.uhn.fhir.model.api.IElement;
@Target(value= {ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface Extension {
String url();
Class<? extends IDatatype> datatype() default NoDatatype.class;
public static class NoDatatype implements IDatatype
{
private NoDatatype() {
// non-instantiable
}
}
}

View File

@ -1,7 +0,0 @@
package ca.uhn.fhir.model.api.annotation;
public @interface ExtensionBlock {
String url();
}

View File

@ -34,28 +34,28 @@ import ca.uhn.fhir.model.datatype.*;
@DatatypeDef(name="Address")
public class AddressDt extends BaseCompositeDatatype {
@Child(name="use", order=0, min=0, max=1)
@Child(name="use", type=CodeDt.class, order=0, min=0, max=1)
private CodeDt myUse;
@Child(name="text", order=1, min=0, max=1)
@Child(name="text", type=StringDt.class, order=1, min=0, max=1)
private StringDt myText;
@Child(name="line", order=2, min=0, max=Child.MAX_UNLIMITED)
@Child(name="line", type=StringDt.class, order=2, min=0, max=Child.MAX_UNLIMITED)
private List<StringDt> myLine;
@Child(name="city", order=3, min=0, max=1)
@Child(name="city", type=StringDt.class, order=3, min=0, max=1)
private StringDt myCity;
@Child(name="state", order=4, min=0, max=1)
@Child(name="state", type=StringDt.class, order=4, min=0, max=1)
private StringDt myState;
@Child(name="zip", order=5, min=0, max=1)
@Child(name="zip", type=StringDt.class, order=5, min=0, max=1)
private StringDt myZip;
@Child(name="country", order=6, min=0, max=1)
@Child(name="country", type=StringDt.class, order=6, min=0, max=1)
private StringDt myCountry;
@Child(name="period", order=7, min=0, max=1)
@Child(name="period", type=PeriodDt.class, order=7, min=0, max=1)
private PeriodDt myPeriod;
/**

View File

@ -34,16 +34,16 @@ import ca.uhn.fhir.model.datatype.*;
@DatatypeDef(name="Contact")
public class ContactDt extends BaseCompositeDatatype {
@Child(name="system", order=0, min=0, max=1)
@Child(name="system", type=CodeDt.class, order=0, min=0, max=1)
private CodeDt mySystem;
@Child(name="value", order=1, min=0, max=1)
@Child(name="value", type=StringDt.class, order=1, min=0, max=1)
private StringDt myValue;
@Child(name="use", order=2, min=0, max=1)
@Child(name="use", type=CodeDt.class, order=2, min=0, max=1)
private CodeDt myUse;
@Child(name="period", order=3, min=0, max=1)
@Child(name="period", type=PeriodDt.class, order=3, min=0, max=1)
private PeriodDt myPeriod;
/**

View File

@ -34,25 +34,25 @@ import ca.uhn.fhir.model.datatype.*;
@DatatypeDef(name="HumanName")
public class HumanNameDt extends BaseCompositeDatatype {
@Child(name="use", order=0, min=0, max=1)
@Child(name="use", type=CodeDt.class, order=0, min=0, max=1)
private CodeDt myUse;
@Child(name="text", order=1, min=0, max=1)
@Child(name="text", type=StringDt.class, order=1, min=0, max=1)
private StringDt myText;
@Child(name="family", order=2, min=0, max=Child.MAX_UNLIMITED)
@Child(name="family", type=StringDt.class, order=2, min=0, max=Child.MAX_UNLIMITED)
private List<StringDt> myFamily;
@Child(name="given", order=3, min=0, max=Child.MAX_UNLIMITED)
@Child(name="given", type=StringDt.class, order=3, min=0, max=Child.MAX_UNLIMITED)
private List<StringDt> myGiven;
@Child(name="prefix", order=4, min=0, max=Child.MAX_UNLIMITED)
@Child(name="prefix", type=StringDt.class, order=4, min=0, max=Child.MAX_UNLIMITED)
private List<StringDt> myPrefix;
@Child(name="suffix", order=5, min=0, max=Child.MAX_UNLIMITED)
@Child(name="suffix", type=StringDt.class, order=5, min=0, max=Child.MAX_UNLIMITED)
private List<StringDt> mySuffix;
@Child(name="period", order=6, min=0, max=1)
@Child(name="period", type=PeriodDt.class, order=6, min=0, max=1)
private PeriodDt myPeriod;
/**

View File

@ -34,10 +34,10 @@ import ca.uhn.fhir.model.datatype.*;
@DatatypeDef(name="Narrative")
public class NarrativeDt extends BaseCompositeDatatype {
@Child(name="status", order=0, min=1, max=1)
@Child(name="status", type=CodeDt.class, order=0, min=1, max=1)
private CodeDt myStatus;
@Child(name="div", order=1, min=1, max=1)
@Child(name="div", type=XhtmlDt.class, order=1, min=1, max=1)
private XhtmlDt myDiv;
/**

View File

@ -34,19 +34,19 @@ import ca.uhn.fhir.model.datatype.*;
@DatatypeDef(name="Quantity")
public class QuantityDt extends BaseCompositeDatatype {
@Child(name="value", order=0, min=0, max=1)
@Child(name="value", type=DecimalDt.class, order=0, min=0, max=1)
private DecimalDt myValue;
@Child(name="comparator", order=1, min=0, max=1)
@Child(name="comparator", type=CodeDt.class, order=1, min=0, max=1)
private CodeDt myComparator;
@Child(name="units", order=2, min=0, max=1)
@Child(name="units", type=StringDt.class, order=2, min=0, max=1)
private StringDt myUnits;
@Child(name="system", order=3, min=0, max=1)
@Child(name="system", type=UriDt.class, order=3, min=0, max=1)
private UriDt mySystem;
@Child(name="code", order=4, min=0, max=1)
@Child(name="code", type=CodeDt.class, order=4, min=0, max=1)
private CodeDt myCode;
/**

View File

@ -34,7 +34,7 @@ import ca.uhn.fhir.model.datatype.*;
@ResourceDef(name="Observation")
public class Observation extends BaseResource {
@Child(name="name", order=0, min=1, max=1)
@Child(name="name", type=CodeableConceptDt.class, order=0, min=1, max=1)
private CodeableConceptDt myName;
@Child(name="value", order=1, min=0, max=1, choice=@Choice(types= {
@ -48,10 +48,10 @@ public class Observation extends BaseResource {
}))
private IDatatype myValue;
@Child(name="interpretation", order=2, min=0, max=1)
@Child(name="interpretation", type=CodeableConceptDt.class, order=2, min=0, max=1)
private CodeableConceptDt myInterpretation;
@Child(name="comments", order=3, min=0, max=1)
@Child(name="comments", type=StringDt.class, order=3, min=0, max=1)
private StringDt myComments;
@Child(name="applies", order=4, min=0, max=1, choice=@Choice(types= {
@ -60,22 +60,22 @@ public class Observation extends BaseResource {
}))
private IDatatype myApplies;
@Child(name="issued", order=5, min=0, max=1)
@Child(name="issued", type=InstantDt.class, order=5, min=0, max=1)
private InstantDt myIssued;
@Child(name="status", order=6, min=1, max=1)
@Child(name="status", type=CodeDt.class, order=6, min=1, max=1)
private CodeDt myStatus;
@Child(name="reliability", order=7, min=1, max=1)
@Child(name="reliability", type=CodeDt.class, order=7, min=1, max=1)
private CodeDt myReliability;
@Child(name="bodySite", order=8, min=0, max=1)
@Child(name="bodySite", type=CodeableConceptDt.class, order=8, min=0, max=1)
private CodeableConceptDt myBodySite;
@Child(name="method", order=9, min=0, max=1)
@Child(name="method", type=CodeableConceptDt.class, order=9, min=0, max=1)
private CodeableConceptDt myMethod;
@Child(name="identifier", order=10, min=0, max=1)
@Child(name="identifier", type=IdentifierDt.class, order=10, min=0, max=1)
private IdentifierDt myIdentifier;
@Child(name="subject", order=11, min=0, max=1)
@ -502,7 +502,7 @@ public class Observation extends BaseResource {
*/
@Block(name="Observation.referenceRange")
public static class ReferenceRange implements IResourceBlock {
@Child(name="name", order=0, min=1, max=1)
@Child(name="name", type=CodeableConceptDt.class, order=0, min=1, max=1)
private CodeableConceptDt myName;
@Child(name="value", order=1, min=0, max=1, choice=@Choice(types= {
@ -516,10 +516,10 @@ public class Observation extends BaseResource {
}))
private IDatatype myValue;
@Child(name="interpretation", order=2, min=0, max=1)
@Child(name="interpretation", type=CodeableConceptDt.class, order=2, min=0, max=1)
private CodeableConceptDt myInterpretation;
@Child(name="comments", order=3, min=0, max=1)
@Child(name="comments", type=StringDt.class, order=3, min=0, max=1)
private StringDt myComments;
@Child(name="applies", order=4, min=0, max=1, choice=@Choice(types= {
@ -528,22 +528,22 @@ public class Observation extends BaseResource {
}))
private IDatatype myApplies;
@Child(name="issued", order=5, min=0, max=1)
@Child(name="issued", type=InstantDt.class, order=5, min=0, max=1)
private InstantDt myIssued;
@Child(name="status", order=6, min=1, max=1)
@Child(name="status", type=CodeDt.class, order=6, min=1, max=1)
private CodeDt myStatus;
@Child(name="reliability", order=7, min=1, max=1)
@Child(name="reliability", type=CodeDt.class, order=7, min=1, max=1)
private CodeDt myReliability;
@Child(name="bodySite", order=8, min=0, max=1)
@Child(name="bodySite", type=CodeableConceptDt.class, order=8, min=0, max=1)
private CodeableConceptDt myBodySite;
@Child(name="method", order=9, min=0, max=1)
@Child(name="method", type=CodeableConceptDt.class, order=9, min=0, max=1)
private CodeableConceptDt myMethod;
@Child(name="identifier", order=10, min=0, max=1)
@Child(name="identifier", type=IdentifierDt.class, order=10, min=0, max=1)
private IdentifierDt myIdentifier;
@Child(name="subject", order=11, min=0, max=1)
@ -971,7 +971,7 @@ public class Observation extends BaseResource {
*/
@Block(name="Observation.related")
public static class Related implements IResourceBlock {
@Child(name="name", order=0, min=1, max=1)
@Child(name="name", type=CodeableConceptDt.class, order=0, min=1, max=1)
private CodeableConceptDt myName;
@Child(name="value", order=1, min=0, max=1, choice=@Choice(types= {
@ -985,10 +985,10 @@ public class Observation extends BaseResource {
}))
private IDatatype myValue;
@Child(name="interpretation", order=2, min=0, max=1)
@Child(name="interpretation", type=CodeableConceptDt.class, order=2, min=0, max=1)
private CodeableConceptDt myInterpretation;
@Child(name="comments", order=3, min=0, max=1)
@Child(name="comments", type=StringDt.class, order=3, min=0, max=1)
private StringDt myComments;
@Child(name="applies", order=4, min=0, max=1, choice=@Choice(types= {
@ -997,22 +997,22 @@ public class Observation extends BaseResource {
}))
private IDatatype myApplies;
@Child(name="issued", order=5, min=0, max=1)
@Child(name="issued", type=InstantDt.class, order=5, min=0, max=1)
private InstantDt myIssued;
@Child(name="status", order=6, min=1, max=1)
@Child(name="status", type=CodeDt.class, order=6, min=1, max=1)
private CodeDt myStatus;
@Child(name="reliability", order=7, min=1, max=1)
@Child(name="reliability", type=CodeDt.class, order=7, min=1, max=1)
private CodeDt myReliability;
@Child(name="bodySite", order=8, min=0, max=1)
@Child(name="bodySite", type=CodeableConceptDt.class, order=8, min=0, max=1)
private CodeableConceptDt myBodySite;
@Child(name="method", order=9, min=0, max=1)
@Child(name="method", type=CodeableConceptDt.class, order=9, min=0, max=1)
private CodeableConceptDt myMethod;
@Child(name="identifier", order=10, min=0, max=1)
@Child(name="identifier", type=IdentifierDt.class, order=10, min=0, max=1)
private IdentifierDt myIdentifier;
@Child(name="subject", order=11, min=0, max=1)

View File

@ -18,7 +18,7 @@ import ca.uhn.fhir.model.api.annotation.*;
import ca.uhn.fhir.model.datatype.*;
/**
* HAPI/FHIR <b>Patient</b> Resource
* HAPI/FHIR <b>ResourceWithExtensionsA</b> Resource
* (Information about a person or animal receiving health care services)
*
* <p>
@ -31,26 +31,30 @@ import ca.uhn.fhir.model.datatype.*;
* Tracking patient is the center of the healthcare process
* </p>
*/
@ResourceDef(name="Patient")
@ResourceDef(name="ResourceWithExtensionsA")
public class Patient extends BaseResource {
@Child()
private Foo1 myFoo1;
@Child()
private Bar1 myBar1;
@Child(name="identifier", order=0, min=0, max=Child.MAX_UNLIMITED)
@Child(name="foo1", type=StringDt.class, order=0, min=0, max=Child.MAX_UNLIMITED)
@Extension(url="http://foo/1")
private List<StringDt> myFoo1;
@Child(name="bar1", type=Bar1.class, order=1, min=0, max=Child.MAX_UNLIMITED)
@Extension(url="http://bar/1")
private List<Bar1> myBar1;
@Child(name="identifier", type=IdentifierDt.class, order=0, min=0, max=Child.MAX_UNLIMITED)
private List<IdentifierDt> myIdentifier;
@Child(name="name", order=1, min=0, max=Child.MAX_UNLIMITED)
@Child(name="name", type=HumanNameDt.class, order=1, min=0, max=Child.MAX_UNLIMITED)
private List<HumanNameDt> myName;
@Child(name="telecom", order=2, min=0, max=Child.MAX_UNLIMITED)
@Child(name="telecom", type=ContactDt.class, order=2, min=0, max=Child.MAX_UNLIMITED)
private List<ContactDt> myTelecom;
@Child(name="gender", order=3, min=0, max=1)
@Child(name="gender", type=CodeableConceptDt.class, order=3, min=0, max=1)
private CodeableConceptDt myGender;
@Child(name="birthDate", order=4, min=0, max=1)
@Child(name="birthDate", type=DateTimeDt.class, order=4, min=0, max=1)
private DateTimeDt myBirthDate;
@Child(name="deceased", order=5, min=0, max=1, choice=@Choice(types= {
@ -59,10 +63,10 @@ public class Patient extends BaseResource {
}))
private IDatatype myDeceased;
@Child(name="address", order=6, min=0, max=Child.MAX_UNLIMITED)
@Child(name="address", type=AddressDt.class, order=6, min=0, max=Child.MAX_UNLIMITED)
private List<AddressDt> myAddress;
@Child(name="maritalStatus", order=7, min=0, max=1)
@Child(name="maritalStatus", type=CodeableConceptDt.class, order=7, min=0, max=1)
private CodeableConceptDt myMaritalStatus;
@Child(name="multipleBirth", order=8, min=0, max=1, choice=@Choice(types= {
@ -71,7 +75,7 @@ public class Patient extends BaseResource {
}))
private IDatatype myMultipleBirth;
@Child(name="photo", order=9, min=0, max=Child.MAX_UNLIMITED)
@Child(name="photo", type=AttachmentDt.class, order=9, min=0, max=Child.MAX_UNLIMITED)
private List<AttachmentDt> myPhoto;
@Child(name="contact", order=10, min=0, max=Child.MAX_UNLIMITED)
@ -80,7 +84,7 @@ public class Patient extends BaseResource {
@Child(name="animal", order=11, min=0, max=1)
private Animal myAnimal;
@Child(name="communication", order=12, min=0, max=Child.MAX_UNLIMITED)
@Child(name="communication", type=CodeableConceptDt.class, order=12, min=0, max=Child.MAX_UNLIMITED)
private List<CodeableConceptDt> myCommunication;
@Child(name="careProvider", order=13, min=0, max=Child.MAX_UNLIMITED)
@ -99,7 +103,7 @@ public class Patient extends BaseResource {
@Child(name="link", order=15, min=0, max=Child.MAX_UNLIMITED)
private List<IDatatype> myLink;
@Child(name="active", order=16, min=0, max=1)
@Child(name="active", type=BooleanDt.class, order=16, min=0, max=1)
private BooleanDt myActive;
/**
@ -415,11 +419,11 @@ public class Patient extends BaseResource {
}
/**
* Gets the value(s) for careProvider (Patient's nominated care provider)
* Gets the value(s) for careProvider (ResourceWithExtensionsA's nominated care provider)
*
* <p>
* <b>Definition:</b>
* Patient's nominated care provider
* ResourceWithExtensionsA's nominated care provider
* </p>
*/
public List<ResourceReference> getCareProvider() {
@ -427,11 +431,11 @@ public class Patient extends BaseResource {
}
/**
* Sets the value(s) for careProvider (Patient's nominated care provider)
* Sets the value(s) for careProvider (ResourceWithExtensionsA's nominated care provider)
*
* <p>
* <b>Definition:</b>
* Patient's nominated care provider
* ResourceWithExtensionsA's nominated care provider
* </p>
*/
public void setCareProvider(List<ResourceReference> theValue) {
@ -512,28 +516,28 @@ public class Patient extends BaseResource {
/**
* Block class for child element: <b>Patient.contact</b> (A contact party (e.g. guardian, partner, friend) for the patient)
* Block class for child element: <b>ResourceWithExtensionsA.contact</b> (A contact party (e.g. guardian, partner, friend) for the patient)
*
* <p>
* <b>Definition:</b>
* A contact party (e.g. guardian, partner, friend) for the patient
* </p>
*/
@Block(name="Patient.contact")
@Block(name="ResourceWithExtensionsA.contact")
public static class Contact implements IResourceBlock {
@Child(name="identifier", order=0, min=0, max=Child.MAX_UNLIMITED)
@Child(name="identifier", type=IdentifierDt.class, order=0, min=0, max=Child.MAX_UNLIMITED)
private List<IdentifierDt> myIdentifier;
@Child(name="name", order=1, min=0, max=Child.MAX_UNLIMITED)
@Child(name="name", type=HumanNameDt.class, order=1, min=0, max=Child.MAX_UNLIMITED)
private List<HumanNameDt> myName;
@Child(name="telecom", order=2, min=0, max=Child.MAX_UNLIMITED)
@Child(name="telecom", type=ContactDt.class, order=2, min=0, max=Child.MAX_UNLIMITED)
private List<ContactDt> myTelecom;
@Child(name="gender", order=3, min=0, max=1)
@Child(name="gender", type=CodeableConceptDt.class, order=3, min=0, max=1)
private CodeableConceptDt myGender;
@Child(name="birthDate", order=4, min=0, max=1)
@Child(name="birthDate", type=DateTimeDt.class, order=4, min=0, max=1)
private DateTimeDt myBirthDate;
@Child(name="deceased", order=5, min=0, max=1, choice=@Choice(types= {
@ -542,10 +546,10 @@ public class Patient extends BaseResource {
}))
private IDatatype myDeceased;
@Child(name="address", order=6, min=0, max=Child.MAX_UNLIMITED)
@Child(name="address", type=AddressDt.class, order=6, min=0, max=Child.MAX_UNLIMITED)
private List<AddressDt> myAddress;
@Child(name="maritalStatus", order=7, min=0, max=1)
@Child(name="maritalStatus", type=CodeableConceptDt.class, order=7, min=0, max=1)
private CodeableConceptDt myMaritalStatus;
@Child(name="multipleBirth", order=8, min=0, max=1, choice=@Choice(types= {
@ -554,7 +558,7 @@ public class Patient extends BaseResource {
}))
private IDatatype myMultipleBirth;
@Child(name="photo", order=9, min=0, max=Child.MAX_UNLIMITED)
@Child(name="photo", type=AttachmentDt.class, order=9, min=0, max=Child.MAX_UNLIMITED)
private List<AttachmentDt> myPhoto;
@Child(name="contact", order=10, min=0, max=Child.MAX_UNLIMITED)
@ -563,7 +567,7 @@ public class Patient extends BaseResource {
@Child(name="animal", order=11, min=0, max=1)
private Animal myAnimal;
@Child(name="communication", order=12, min=0, max=Child.MAX_UNLIMITED)
@Child(name="communication", type=CodeableConceptDt.class, order=12, min=0, max=Child.MAX_UNLIMITED)
private List<CodeableConceptDt> myCommunication;
@Child(name="careProvider", order=13, min=0, max=Child.MAX_UNLIMITED)
@ -582,7 +586,7 @@ public class Patient extends BaseResource {
@Child(name="link", order=15, min=0, max=Child.MAX_UNLIMITED)
private List<IDatatype> myLink;
@Child(name="active", order=16, min=0, max=1)
@Child(name="active", type=BooleanDt.class, order=16, min=0, max=1)
private BooleanDt myActive;
/**
@ -898,11 +902,11 @@ public class Patient extends BaseResource {
}
/**
* Gets the value(s) for careProvider (Patient's nominated care provider)
* Gets the value(s) for careProvider (ResourceWithExtensionsA's nominated care provider)
*
* <p>
* <b>Definition:</b>
* Patient's nominated care provider
* ResourceWithExtensionsA's nominated care provider
* </p>
*/
public List<ResourceReference> getCareProvider() {
@ -910,11 +914,11 @@ public class Patient extends BaseResource {
}
/**
* Sets the value(s) for careProvider (Patient's nominated care provider)
* Sets the value(s) for careProvider (ResourceWithExtensionsA's nominated care provider)
*
* <p>
* <b>Definition:</b>
* Patient's nominated care provider
* ResourceWithExtensionsA's nominated care provider
* </p>
*/
public void setCareProvider(List<ResourceReference> theValue) {
@ -996,28 +1000,28 @@ public class Patient extends BaseResource {
}
/**
* Block class for child element: <b>Patient.animal</b> (If this patient is an animal (non-human))
* Block class for child element: <b>ResourceWithExtensionsA.animal</b> (If this patient is an animal (non-human))
*
* <p>
* <b>Definition:</b>
* This element has a value if the patient is an animal
* </p>
*/
@Block(name="Patient.animal")
@Block(name="ResourceWithExtensionsA.animal")
public static class Animal implements IResourceBlock {
@Child(name="identifier", order=0, min=0, max=Child.MAX_UNLIMITED)
@Child(name="identifier", type=IdentifierDt.class, order=0, min=0, max=Child.MAX_UNLIMITED)
private List<IdentifierDt> myIdentifier;
@Child(name="name", order=1, min=0, max=Child.MAX_UNLIMITED)
@Child(name="name", type=HumanNameDt.class, order=1, min=0, max=Child.MAX_UNLIMITED)
private List<HumanNameDt> myName;
@Child(name="telecom", order=2, min=0, max=Child.MAX_UNLIMITED)
@Child(name="telecom", type=ContactDt.class, order=2, min=0, max=Child.MAX_UNLIMITED)
private List<ContactDt> myTelecom;
@Child(name="gender", order=3, min=0, max=1)
@Child(name="gender", type=CodeableConceptDt.class, order=3, min=0, max=1)
private CodeableConceptDt myGender;
@Child(name="birthDate", order=4, min=0, max=1)
@Child(name="birthDate", type=DateTimeDt.class, order=4, min=0, max=1)
private DateTimeDt myBirthDate;
@Child(name="deceased", order=5, min=0, max=1, choice=@Choice(types= {
@ -1026,10 +1030,10 @@ public class Patient extends BaseResource {
}))
private IDatatype myDeceased;
@Child(name="address", order=6, min=0, max=Child.MAX_UNLIMITED)
@Child(name="address", type=AddressDt.class, order=6, min=0, max=Child.MAX_UNLIMITED)
private List<AddressDt> myAddress;
@Child(name="maritalStatus", order=7, min=0, max=1)
@Child(name="maritalStatus", type=CodeableConceptDt.class, order=7, min=0, max=1)
private CodeableConceptDt myMaritalStatus;
@Child(name="multipleBirth", order=8, min=0, max=1, choice=@Choice(types= {
@ -1038,7 +1042,7 @@ public class Patient extends BaseResource {
}))
private IDatatype myMultipleBirth;
@Child(name="photo", order=9, min=0, max=Child.MAX_UNLIMITED)
@Child(name="photo", type=AttachmentDt.class, order=9, min=0, max=Child.MAX_UNLIMITED)
private List<AttachmentDt> myPhoto;
@Child(name="contact", order=10, min=0, max=Child.MAX_UNLIMITED)
@ -1047,7 +1051,7 @@ public class Patient extends BaseResource {
@Child(name="animal", order=11, min=0, max=1)
private Animal myAnimal;
@Child(name="communication", order=12, min=0, max=Child.MAX_UNLIMITED)
@Child(name="communication", type=CodeableConceptDt.class, order=12, min=0, max=Child.MAX_UNLIMITED)
private List<CodeableConceptDt> myCommunication;
@Child(name="careProvider", order=13, min=0, max=Child.MAX_UNLIMITED)
@ -1066,7 +1070,7 @@ public class Patient extends BaseResource {
@Child(name="link", order=15, min=0, max=Child.MAX_UNLIMITED)
private List<IDatatype> myLink;
@Child(name="active", order=16, min=0, max=1)
@Child(name="active", type=BooleanDt.class, order=16, min=0, max=1)
private BooleanDt myActive;
/**
@ -1382,11 +1386,11 @@ public class Patient extends BaseResource {
}
/**
* Gets the value(s) for careProvider (Patient's nominated care provider)
* Gets the value(s) for careProvider (ResourceWithExtensionsA's nominated care provider)
*
* <p>
* <b>Definition:</b>
* Patient's nominated care provider
* ResourceWithExtensionsA's nominated care provider
* </p>
*/
public List<ResourceReference> getCareProvider() {
@ -1394,11 +1398,11 @@ public class Patient extends BaseResource {
}
/**
* Sets the value(s) for careProvider (Patient's nominated care provider)
* Sets the value(s) for careProvider (ResourceWithExtensionsA's nominated care provider)
*
* <p>
* <b>Definition:</b>
* Patient's nominated care provider
* ResourceWithExtensionsA's nominated care provider
* </p>
*/
public void setCareProvider(List<ResourceReference> theValue) {
@ -1480,28 +1484,28 @@ public class Patient extends BaseResource {
}
/**
* Block class for child element: <b>Patient.link</b> (Link to another patient resource that concerns the same actual person)
* Block class for child element: <b>ResourceWithExtensionsA.link</b> (Link to another patient resource that concerns the same actual person)
*
* <p>
* <b>Definition:</b>
* Link to another patient resource that concerns the same actual person
* </p>
*/
@Block(name="Patient.link")
@Block(name="ResourceWithExtensionsA.link")
public static class Link implements IResourceBlock {
@Child(name="identifier", order=0, min=0, max=Child.MAX_UNLIMITED)
@Child(name="identifier", type=IdentifierDt.class, order=0, min=0, max=Child.MAX_UNLIMITED)
private List<IdentifierDt> myIdentifier;
@Child(name="name", order=1, min=0, max=Child.MAX_UNLIMITED)
@Child(name="name", type=HumanNameDt.class, order=1, min=0, max=Child.MAX_UNLIMITED)
private List<HumanNameDt> myName;
@Child(name="telecom", order=2, min=0, max=Child.MAX_UNLIMITED)
@Child(name="telecom", type=ContactDt.class, order=2, min=0, max=Child.MAX_UNLIMITED)
private List<ContactDt> myTelecom;
@Child(name="gender", order=3, min=0, max=1)
@Child(name="gender", type=CodeableConceptDt.class, order=3, min=0, max=1)
private CodeableConceptDt myGender;
@Child(name="birthDate", order=4, min=0, max=1)
@Child(name="birthDate", type=DateTimeDt.class, order=4, min=0, max=1)
private DateTimeDt myBirthDate;
@Child(name="deceased", order=5, min=0, max=1, choice=@Choice(types= {
@ -1510,10 +1514,10 @@ public class Patient extends BaseResource {
}))
private IDatatype myDeceased;
@Child(name="address", order=6, min=0, max=Child.MAX_UNLIMITED)
@Child(name="address", type=AddressDt.class, order=6, min=0, max=Child.MAX_UNLIMITED)
private List<AddressDt> myAddress;
@Child(name="maritalStatus", order=7, min=0, max=1)
@Child(name="maritalStatus", type=CodeableConceptDt.class, order=7, min=0, max=1)
private CodeableConceptDt myMaritalStatus;
@Child(name="multipleBirth", order=8, min=0, max=1, choice=@Choice(types= {
@ -1522,7 +1526,7 @@ public class Patient extends BaseResource {
}))
private IDatatype myMultipleBirth;
@Child(name="photo", order=9, min=0, max=Child.MAX_UNLIMITED)
@Child(name="photo", type=AttachmentDt.class, order=9, min=0, max=Child.MAX_UNLIMITED)
private List<AttachmentDt> myPhoto;
@Child(name="contact", order=10, min=0, max=Child.MAX_UNLIMITED)
@ -1531,7 +1535,7 @@ public class Patient extends BaseResource {
@Child(name="animal", order=11, min=0, max=1)
private Animal myAnimal;
@Child(name="communication", order=12, min=0, max=Child.MAX_UNLIMITED)
@Child(name="communication", type=CodeableConceptDt.class, order=12, min=0, max=Child.MAX_UNLIMITED)
private List<CodeableConceptDt> myCommunication;
@Child(name="careProvider", order=13, min=0, max=Child.MAX_UNLIMITED)
@ -1550,7 +1554,7 @@ public class Patient extends BaseResource {
@Child(name="link", order=15, min=0, max=Child.MAX_UNLIMITED)
private List<IDatatype> myLink;
@Child(name="active", order=16, min=0, max=1)
@Child(name="active", type=BooleanDt.class, order=16, min=0, max=1)
private BooleanDt myActive;
/**
@ -1866,11 +1870,11 @@ public class Patient extends BaseResource {
}
/**
* Gets the value(s) for careProvider (Patient's nominated care provider)
* Gets the value(s) for careProvider (ResourceWithExtensionsA's nominated care provider)
*
* <p>
* <b>Definition:</b>
* Patient's nominated care provider
* ResourceWithExtensionsA's nominated care provider
* </p>
*/
public List<ResourceReference> getCareProvider() {
@ -1878,11 +1882,11 @@ public class Patient extends BaseResource {
}
/**
* Sets the value(s) for careProvider (Patient's nominated care provider)
* Sets the value(s) for careProvider (ResourceWithExtensionsA's nominated care provider)
*
* <p>
* <b>Definition:</b>
* Patient's nominated care provider
* ResourceWithExtensionsA's nominated care provider
* </p>
*/
public void setCareProvider(List<ResourceReference> theValue) {
@ -1964,33 +1968,18 @@ public class Patient extends BaseResource {
}
@ExtensionBlock(url="http://foo/1")
public class Foo1 implements IExtension {
@Block(name="Bar1")
public static class Bar1 implements IExtension {
@Child(name="value", order=0)
private StringDt myValue;
@Child(name="bar11", type=DateDt.class, order=0, min=0, max=Child.MAX_UNLIMITED)
@Extension(url="http://bar/1/1")
private List<DateDt> myBar11;
/**
* Gets the value
*/
public StringDt getValue() {
return myValue;
}
/**
* Sets the value
*/
public void setValue(StringDt theValue) {
myValue = theValue;
}
@Child(name="bar12", type=DateDt.class, order=1, min=0, max=Child.MAX_UNLIMITED)
@Extension(url="http://bar/1/2")
private List<DateDt> myBar12;
}
@ExtensionBlock(url="http://bar/1")
public class Bar1 implements IExtension {
}

View File

@ -12,6 +12,7 @@ import ca.uhn.fhir.context.BaseRuntimeChildDefinition;
import ca.uhn.fhir.context.BaseRuntimeElementCompositeDefinition;
import ca.uhn.fhir.context.BaseRuntimeElementDefinition;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.context.RuntimeChildDeclaredExtensionDefinition;
import ca.uhn.fhir.context.RuntimePrimitiveDatatypeDefinition;
import ca.uhn.fhir.context.RuntimePrimitiveDatatypeNarrativeDefinition;
import ca.uhn.fhir.context.RuntimeResourceBlockDefinition;
@ -30,6 +31,96 @@ import ca.uhn.fhir.model.datatype.XhtmlDt;
class ParserState {
public class DeclaredExtensionState extends BaseState {
private RuntimeChildDeclaredExtensionDefinition myDefinition;
private IElement myParentInstance;
private IElement myChildInstance;
public DeclaredExtensionState(RuntimeChildDeclaredExtensionDefinition theDefinition, IElement theParentInstance) {
myDefinition = theDefinition;
myParentInstance = theParentInstance;
}
@Override
public void attributeValue(Attribute theAttribute, String theValue) throws DataFormatException {
throw new DataFormatException("'value' attribute is invalid in 'extension' element");
}
@Override
public void endingElement(EndElement theElem) throws DataFormatException {
pop();
}
@Override
public void enteringNewElementExtension(StartElement theElement, String theUrlAttr) {
RuntimeChildDeclaredExtensionDefinition declaredExtension = myDefinition.getChildExtensionForUrl(theUrlAttr);
if (declaredExtension != null) {
if (myChildInstance == null) {
myChildInstance = myDefinition.newInstance();
myDefinition.getMutator().addValue(myParentInstance, myChildInstance);
}
BaseState newState = new DeclaredExtensionState(declaredExtension, myChildInstance);
push(newState);
}else {
super.enteringNewElementExtension(theElement, theUrlAttr);
}
}
@Override
public void enteringNewElement(StartElement theElement, String theLocalPart) throws DataFormatException {
BaseRuntimeElementDefinition<?> target = myDefinition.getChildByName(theLocalPart);
if (target == null) {
throw new DataFormatException("Unknown extension element name: " + theLocalPart);
}
switch (target.getChildType()) {
case COMPOSITE_DATATYPE: {
BaseRuntimeElementCompositeDefinition<?> compositeTarget = (BaseRuntimeElementCompositeDefinition<?>) target;
ICompositeDatatype newChildInstance = (ICompositeDatatype) compositeTarget.newInstance();
myDefinition.getMutator().addValue(myParentInstance, newChildInstance);
ContainerState newState = new ContainerState(compositeTarget, newChildInstance);
push(newState);
return;
}
case PRIMITIVE_DATATYPE: {
RuntimePrimitiveDatatypeDefinition primitiveTarget = (RuntimePrimitiveDatatypeDefinition) target;
IPrimitiveDatatype<?> newChildInstance = primitiveTarget.newInstance();
myDefinition.getMutator().addValue(myParentInstance, newChildInstance);
PrimitiveState newState = new PrimitiveState(newChildInstance);
push(newState);
return;
}
case RESOURCE_REF: {
RuntimeResourceReferenceDefinition resourceRefTarget = (RuntimeResourceReferenceDefinition) target;
ResourceReference newChildInstance = new ResourceReference();
myDefinition.getMutator().addValue(myParentInstance, newChildInstance);
ResourceReferenceState newState = new ResourceReferenceState(resourceRefTarget, newChildInstance);
push(newState);
return;
}
case PRIMITIVE_XHTML:
case RESOURCE:
case RESOURCE_BLOCK:
case UNDECL_EXT:
case EXTENSION_DECLARED:
default:
break;
}
}
@Override
public void otherEvent(XMLEvent theEvent) throws DataFormatException {
// ignore
}
@Override
protected IElement getCurrentElement() {
return myParentInstance;
}
}
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(ParserState.class);
private FhirContext myContext;
@ -106,12 +197,14 @@ class ParserState {
public abstract void enteringNewElement(StartElement theElement, String theLocalPart) throws DataFormatException;
/**
* Default implementation just handles undeclared extensions
*/
public void enteringNewElementExtension(@SuppressWarnings("unused") StartElement theElement, String theUrlAttr) {
// TODO: handle predefined extensions
if (getCurrentElement() instanceof ISupportsUndeclaredExtensions) {
UndeclaredExtension newExtension = new UndeclaredExtension();
newExtension.setUrl(theUrlAttr);
// TODO: fail if we don't support undeclared extensions
((ISupportsUndeclaredExtensions) getCurrentElement()).getUndeclaredExtensions().add(newExtension);
ExtensionState newState = new ExtensionState(newExtension);
push(newState);
@ -151,6 +244,17 @@ class ParserState {
}
}
@Override
public void enteringNewElementExtension(StartElement theElement, String theUrlAttr) {
RuntimeChildDeclaredExtensionDefinition declaredExtension = myDefinition.getDeclaredExtension(theUrlAttr);
if (declaredExtension != null) {
BaseState newState = new DeclaredExtensionState(declaredExtension, myInstance);
push(newState);
}else {
super.enteringNewElementExtension(theElement, theUrlAttr);
}
}
@Override
public void enteringNewElement(StartElement theElement, String theChildName) throws DataFormatException {
BaseRuntimeChildDefinition child = myDefinition.getChildByNameOrThrowDataFormatException(theChildName);

View File

@ -33,11 +33,10 @@ import ca.uhn.fhir.context.ConfigurationException;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.context.RuntimeChildUndeclaredExtensionDefinition;
import ca.uhn.fhir.context.RuntimeResourceDefinition;
import ca.uhn.fhir.model.api.IExtension;
import ca.uhn.fhir.model.api.ISupportsUndeclaredExtensions;
import ca.uhn.fhir.model.api.IElement;
import ca.uhn.fhir.model.api.IPrimitiveDatatype;
import ca.uhn.fhir.model.api.IResource;
import ca.uhn.fhir.model.api.ISupportsUndeclaredExtensions;
import ca.uhn.fhir.model.api.ResourceReference;
import ca.uhn.fhir.model.api.UndeclaredExtension;
import ca.uhn.fhir.model.datatype.XhtmlDt;
@ -80,9 +79,15 @@ public class XmlParser {
return stringWriter.toString();
}
private void encodeCompositeElementToStreamWriter(IElement theElement, XMLStreamWriter theEventWriter,BaseRuntimeElementCompositeDefinition<?> resDef) throws XMLStreamException, DataFormatException {
private void encodeCompositeElementToStreamWriter(IElement theElement, XMLStreamWriter theEventWriter, BaseRuntimeElementCompositeDefinition<?> resDef) throws XMLStreamException, DataFormatException {
encodeExtensionsIfPresent(theEventWriter, theElement);
for (BaseRuntimeChildDefinition nextChild : resDef.getChildren()) {
encodeCompositeElementChildrenToStreamWriter(theElement, theEventWriter, resDef.getExtensions());
encodeCompositeElementChildrenToStreamWriter(theElement, theEventWriter, resDef.getChildren());
}
private void encodeCompositeElementChildrenToStreamWriter(IElement theElement, XMLStreamWriter theEventWriter, List<? extends BaseRuntimeChildDefinition> children) throws XMLStreamException, DataFormatException {
for (BaseRuntimeChildDefinition nextChild : children) {
List<? extends IElement> values = nextChild.getAccessor().getValues(theElement);
if (values == null || values.isEmpty()) {
continue;
@ -94,14 +99,25 @@ public class XmlParser {
}
Class<? extends IElement> type = nextValue.getClass();
String childName = nextChild.getChildNameByDatatype(type);
String extensionUrl = nextChild.getExtensionUrl();
BaseRuntimeElementDefinition<?> childDef = nextChild.getChildElementDefinitionByDatatype(type);
if (childDef == null) {
throw new IllegalStateException(nextChild + " has no child of type " + type);
}
encodeChildElementToStreamWriter(theEventWriter, nextValue, childName, childDef);
if (extensionUrl != null && childName.equals("extension") == false) {
theEventWriter.writeStartElement("extension");
theEventWriter.writeAttribute("url", extensionUrl);
encodeChildElementToStreamWriter(theEventWriter, nextValue, childName, childDef, null);
theEventWriter.writeEndElement();
} else {
encodeChildElementToStreamWriter(theEventWriter, nextValue, childName, childDef, extensionUrl);
}
}
}
}
private void encodeChildElementToStreamWriter(XMLStreamWriter theEventWriter, IElement nextValue, String childName, BaseRuntimeElementDefinition<?> childDef) throws XMLStreamException, DataFormatException {
private void encodeChildElementToStreamWriter(XMLStreamWriter theEventWriter, IElement nextValue, String childName, BaseRuntimeElementDefinition<?> childDef, String theExtensionUrl) throws XMLStreamException, DataFormatException {
switch (childDef.getChildType()) {
case PRIMITIVE_DATATYPE: {
theEventWriter.writeStartElement(childName);
@ -114,8 +130,11 @@ public class XmlParser {
case RESOURCE_BLOCK:
case COMPOSITE_DATATYPE: {
theEventWriter.writeStartElement(childName);
if (isNotBlank(theExtensionUrl)) {
theEventWriter.writeAttribute("url", theExtensionUrl);
}
BaseRuntimeElementCompositeDefinition<?> childCompositeDef = (BaseRuntimeElementCompositeDefinition<?>) childDef;
encodeCompositeElementToStreamWriter(nextValue, theEventWriter, childCompositeDef);
encodeCompositeElementToStreamWriter(nextValue, theEventWriter, childCompositeDef);
encodeExtensionsIfPresent(theEventWriter, nextValue);
theEventWriter.writeEndElement();
break;
@ -146,18 +165,18 @@ public class XmlParser {
for (UndeclaredExtension next : ((ISupportsUndeclaredExtensions) theResource).getUndeclaredExtensions()) {
theWriter.writeStartElement("extension");
theWriter.writeAttribute("url", next.getUrl());
if (next.getValue() != null) {
IElement nextValue = next.getValue();
RuntimeChildUndeclaredExtensionDefinition extDef = myContext.getRuntimeChildUndeclaredExtensionDefinition();
String childName = extDef.getChildNameByDatatype(nextValue.getClass());
BaseRuntimeElementDefinition<?> childDef = extDef.getChildElementDefinitionByDatatype(nextValue.getClass());
encodeChildElementToStreamWriter(theWriter, nextValue, childName, childDef);
encodeChildElementToStreamWriter(theWriter, nextValue, childName, childDef, null);
}
// child extensions
encodeExtensionsIfPresent(theWriter, next);
theWriter.writeEndElement();
}
}
@ -274,7 +293,7 @@ public class XmlParser {
parserState = ParserState.getResourceInstance(myContext, elem.getName().getLocalPart());
} else if ("extension".equals(elem.getName().getLocalPart())) {
Attribute urlAttr = elem.getAttributeByName(new QName("url"));
if (urlAttr==null||isBlank(urlAttr.getValue())) {
if (urlAttr == null || isBlank(urlAttr.getValue())) {
throw new DataFormatException("Extension element has no 'url' attribute");
}
parserState.enteringNewElementExtension(elem, urlAttr.getValue());

View File

@ -1,16 +1,44 @@
package ca.uhn.fhir.context;
import static org.junit.Assert.*;
import org.junit.Test;
import ca.uhn.fhir.model.resource.Observation;
import ca.uhn.fhir.parser.DataFormatException;
public class ModelScannerTest {
@Test
public void testScanner() {
public void testScanExtensionTypes() throws DataFormatException {
ModelScanner scanner = new ModelScanner(Observation.class);
@SuppressWarnings("unchecked")
ModelScanner scanner = new ModelScanner(ResourceWithExtensionsA.class);
RuntimeResourceDefinition def = (RuntimeResourceDefinition) scanner.getClassToElementDefinitions().get(ResourceWithExtensionsA.class);
assertEquals(RuntimeChildCompositeDatatypeDefinition.class, def.getChildByNameOrThrowDataFormatException("identifier").getClass());
RuntimeChildDeclaredExtensionDefinition ext = def.getDeclaredExtension("http://foo/1");
assertNotNull(ext);
BaseRuntimeElementDefinition<?> valueString = ext.getChildByName("valueString");
assertNotNull(valueString);
ext = def.getDeclaredExtension("http://foo/2");
assertNotNull(ext);
valueString = ext.getChildByName("valueString");
assertNotNull(valueString);
ext = def.getDeclaredExtension("http://bar/1");
assertNotNull(ext);
RuntimeChildDeclaredExtensionDefinition childExt = ext.getChildExtensionForUrl("http://bar/1/1");
assertNotNull(childExt);
BaseRuntimeElementDefinition<?> valueDate = childExt.getChildByName("valueDate");
assertNotNull(valueDate);
childExt = ext.getChildExtensionForUrl("http://bar/1/2");
assertNotNull(childExt);
childExt = childExt.getChildExtensionForUrl("http://baz/1/2/1");
assertNotNull(childExt);
valueDate = childExt.getChildByName("valueDate");
assertNotNull(valueDate);
}

View File

@ -0,0 +1,139 @@
package ca.uhn.fhir.context;
import java.util.List;
import ca.uhn.fhir.model.api.IExtension;
import ca.uhn.fhir.model.api.annotation.Block;
import ca.uhn.fhir.model.api.annotation.Child;
import ca.uhn.fhir.model.api.annotation.Extension;
import ca.uhn.fhir.model.api.annotation.ResourceDef;
import ca.uhn.fhir.model.datatype.DateDt;
import ca.uhn.fhir.model.datatype.IdentifierDt;
import ca.uhn.fhir.model.datatype.StringDt;
import ca.uhn.fhir.model.resource.BaseResource;
@ResourceDef(name = "ResourceWithExtensionsA")
public class ResourceWithExtensionsA extends BaseResource {
@Child(name = "bar1", type = Bar1.class, order = 2, min = 1, max = Child.MAX_UNLIMITED)
@Extension(url = "http://bar/1")
private List<Bar1> myBar1;
@Child(name = "bar2", type = Bar1.class, order = 3, min = 1, max = Child.MAX_UNLIMITED)
@Extension(url = "http://bar/2")
private Bar1 myBar2;
@Child(name = "foo1", type = StringDt.class, order = 0, min = 0, max = Child.MAX_UNLIMITED)
@Extension(url = "http://foo/1")
private List<StringDt> myFoo1;
@Child(name = "foo2", type = StringDt.class, order = 1, min = 0, max = 1)
@Extension(url = "http://foo/2")
private StringDt myFoo2;
@Child(name = "identifier", type = IdentifierDt.class, order = 0, min = 0, max = Child.MAX_UNLIMITED)
private List<IdentifierDt> myIdentifier;
public List<Bar1> getBar1() {
return myBar1;
}
public Bar1 getBar2() {
return myBar2;
}
public List<StringDt> getFoo1() {
return myFoo1;
}
public StringDt getFoo2() {
return myFoo2;
}
public List<IdentifierDt> getIdentifier() {
return myIdentifier;
}
public void setBar1(List<Bar1> theBar1) {
myBar1 = theBar1;
}
public void setBar2(Bar1 theBar2) {
myBar2 = theBar2;
}
public void setFoo1(List<StringDt> theFoo1) {
myFoo1 = theFoo1;
}
public void setFoo2(StringDt theFoo2) {
myFoo2 = theFoo2;
}
public void setIdentifier(List<IdentifierDt> theValue) {
myIdentifier = theValue;
}
@Block(name = "Bar1")
public static class Bar1 implements IExtension {
public Bar1() {
super();
}
@Child(name = "bar11", type = DateDt.class, order = 0, min = 0, max = Child.MAX_UNLIMITED)
@Extension(url = "http://bar/1/1")
private List<DateDt> myBar11;
@Child(name = "bar12", type = DateDt.class, order = 1, min = 0, max = Child.MAX_UNLIMITED)
@Extension(url = "http://bar/1/2")
private List<Bar2> myBar12;
public List<DateDt> getBar11() {
return myBar11;
}
public List<Bar2> getBar12() {
return myBar12;
}
public void setBar11(List<DateDt> theBar11) {
myBar11 = theBar11;
}
public void setBar12(List<Bar2> theBar12) {
myBar12 = theBar12;
}
}
@Block(name = "Bar2")
public static class Bar2 implements IExtension {
@Child(name = "bar121", type = DateDt.class, order = 0, min = 0, max = Child.MAX_UNLIMITED)
@Extension(url = "http://bar/1/2/1")
private List<DateDt> myBar121;
@Child(name = "bar122", type = DateDt.class, order = 1, min = 0, max = Child.MAX_UNLIMITED)
@Extension(url = "http://bar/1/2/2")
private List<DateDt> myBar122;
public List<DateDt> getBar121() {
return myBar121;
}
public List<DateDt> getBar122() {
return myBar122;
}
public void setBar121(List<DateDt> theBar121) {
myBar121 = theBar121;
}
public void setBar122(List<DateDt> theBar122) {
myBar122 = theBar122;
}
}
}

View File

@ -1,28 +1,100 @@
package ca.uhn.fhir.parser;
import static org.junit.Assert.*;
import java.io.IOException;
import java.io.StringReader;
import org.apache.commons.io.IOUtils;
import org.custommonkey.xmlunit.DetailedDiff;
import org.custommonkey.xmlunit.Diff;
import org.custommonkey.xmlunit.XMLUnit;
import org.junit.BeforeClass;
import org.junit.Test;
import org.xml.sax.SAXException;
import ca.uhn.fhir.context.ConfigurationException;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.context.ResourceWithExtensionsA;
import ca.uhn.fhir.model.api.IResource;
import ca.uhn.fhir.model.datatype.DateDt;
import ca.uhn.fhir.model.resource.Observation;
public class XmlParserTest {
@Test
public void testLoadAndEncodeExtensions() throws ConfigurationException, DataFormatException, SAXException, IOException {
FhirContext ctx = new FhirContext(ResourceWithExtensionsA.class);
XmlParser p = new XmlParser(ctx);
//@formatter:off
String msg = "<ResourceWithExtensionsA xmlns=\"http://hl7.org/fhir\">\n" +
" <extension url=\"http://foo/1\">\n" +
" <valueString value=\"Foo1Value\"/>\n" +
" </extension>\n" +
" <extension url=\"http://foo/1\">\n" +
" <valueString value=\"Foo1Value2\"/>\n" +
" </extension>\n" +
" <extension url=\"http://foo/2\">\n" +
" <valueString value=\"Foo2Value1\"/>\n" +
" </extension>\n" +
" <extension url=\"http://bar/1\">\n" +
" <extension url=\"http://bar/1/1\">\n" +
" <valueDate value=\"2013-01-01\"/>\n" +
" </extension>\n" +
" <extension url=\"http://bar/1/2\">\n" +
" <extension url=\"http://bar/1/2/1\">\n" +
" <valueDate value=\"2013-01-02\"/>\n" +
" </extension>\n" +
" <extension url=\"http://bar/1/2/1\">\n" +
" <valueDate value=\"2013-01-12\"/>\n" +
" </extension>\n" +
" <extension url=\"http://bar/1/2/2\">\n" +
" <valueDate value=\"2013-01-03\"/>\n" +
" </extension>\n" +
" </extension>\n" +
" </extension>\n" +
" <identifier>\n" +
" <label value=\"IdentifierLabel\"/>\n" +
" </identifier>\n" +
"</ResourceWithExtensionsA>";
//@formatter:on
ResourceWithExtensionsA resource = (ResourceWithExtensionsA) p.parseResource(msg);
assertEquals("IdentifierLabel", resource.getIdentifier().get(0).getLabel().getValue());
assertEquals("Foo1Value", resource.getFoo1().get(0).getValue());
assertEquals("Foo1Value2", resource.getFoo1().get(1).getValue());
assertEquals("Foo2Value1", resource.getFoo2().getValue());
assertEquals("2013-01-01", resource.getBar1().get(0).getBar11().get(0).getValueAsString());
assertEquals("2013-01-02", resource.getBar1().get(0).getBar12().get(0).getBar121().get(0).getValueAsString());
assertEquals("2013-01-12", resource.getBar1().get(0).getBar12().get(0).getBar121().get(1).getValueAsString());
assertEquals("2013-01-03", resource.getBar1().get(0).getBar12().get(0).getBar122().get(0).getValueAsString());
String encoded = p.encodeResourceToString(resource);
ourLog.info(encoded);
Diff d = new Diff(new StringReader(msg), new StringReader(encoded));
assertTrue(d.toString(), d.identical());
}
@BeforeClass
public static void beforeClass() {
XMLUnit.setIgnoreAttributeOrder(true);
XMLUnit.setIgnoreComments(true);
XMLUnit.setIgnoreWhitespace(true);
}
@Test
public void testLoadObservation() throws ConfigurationException, DataFormatException, IOException {
FhirContext ctx = new FhirContext(Observation.class);
XmlParser p = new XmlParser(ctx);
IResource resource = p.parseResource(IOUtils.toString(XmlParserTest.class.getResourceAsStream("/observation-example-eeg.xml")));
String result = p.encodeResourceToString(resource);
ourLog.info(result);
}
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(XmlParserTest.class);
}

View File

@ -22,10 +22,10 @@
<version>3.10-FINAL</version>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
<version>3.10-FINAL</version>
</dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
<version>3.10-FINAL</version>
</dependency>
<dependency>
<groupId>org.apache.velocity</groupId>
@ -112,7 +112,7 @@
</properties>
<build>
<plugins>
</plugins>
</build>

View File

@ -21,8 +21,6 @@ import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import ca.uhn.fhir.model.api.IDatatype;
import ca.uhn.fhir.model.api.ResourceReference;
import ca.uhn.fhir.starter.model.BaseElement;
import ca.uhn.fhir.starter.model.Child;
import ca.uhn.fhir.starter.model.Extension;
@ -91,41 +89,9 @@ public abstract class BaseParser {
parseBasicElements(nextRow, elem);
if (elem.isResourceRef()) {
elem.setReferenceType(ResourceReference.class.getSimpleName());
} else if (elem.getType().size() == 1) {
String elemName = elem.getType().get(0);
elemName = elemName.substring(0, 1).toUpperCase() + elemName.substring(1);
if (elem instanceof ResourceBlock) {
elem.setReferenceType(elemName);
} else {
elem.setReferenceType(elemName + "Dt");
}
// if
// (elem.getReferenceType().equals(CodeDt.class.getSimpleName())
// ||
// elem.getReferenceType().equals(CodeableConceptDt.class.getSimpleName()))
// {
// elem.setReferenceType(elemName + "Dt<" + elem.getBinding() +
// "Enum>");
// }
} else {
elem.setReferenceType(IDatatype.class.getSimpleName());
}
if (elem.isRepeatable()) {
elem.setReferenceType("List<" + elem.getReferenceType() + ">");
}
for (int childIdx = 0; childIdx < elem.getType().size(); childIdx++) {
String nextType = elem.getType().get(childIdx);
if (elem.isResourceRef()) {
nextType = nextType.substring(0, 1).toUpperCase() + nextType.substring(1);
} else {
nextType = nextType.substring(0, 1).toUpperCase() + nextType.substring(1) + "Dt";
}
nextType = nextType.substring(0, 1).toUpperCase() + nextType.substring(1);
elem.getType().set(childIdx, nextType);
}

View File

@ -60,11 +60,11 @@ public class ResourceParser extends BaseParser {
ResourceParser p = new ResourceParser();
p.setDirectory("src/test/resources/res");
p.setResourceName("patient");
p.setOutputFile("../hapi-fhir-base/src/main/java/ca/uhn/fhir/model/resource/Patient.java");
p.setOutputFile("../hapi-fhir-base/src/main/java/ca/uhn/fhir/model/resource/ResourceWithExtensionsA.java");
ArrayList<Extension> exts = new ArrayList<Extension>();
Extension ext1 = new Extension("foo1", "http://foo/1", StringDt.class);
Extension ext1 = new Extension("foo1", "http://foo/1", "string");
exts.add(ext1);
Extension ext2 = new Extension("bar1", "http://bar/1", new Extension("bar11", "http://bar/1/1", DateDt.class), new Extension("bar12", "http://bar/1/2", DateDt.class));
Extension ext2 = new Extension("bar1", "http://bar/1", new Extension("bar11", "http://bar/1/1", "date"), new Extension("bar12", "http://bar/1/2", "date"));
exts.add(ext2);
p.setExtensions(exts);
p.parse();

View File

@ -142,10 +142,11 @@ public abstract class BaseElement {
public void setTypeFromString(String theType) {
if (theType == null) {
myType=null;
return;
}
String typeString = theType;
if (typeString.startsWith("Resource(")) {
if (typeString.toLowerCase().startsWith("resource(")) {
typeString = typeString.substring("Resource(".length(), typeString.length() - 1);
myResourceRef = true;
}

View File

@ -1,30 +1,74 @@
package ca.uhn.fhir.starter.model;
import java.util.ArrayList;
import java.util.List;
import ca.uhn.fhir.model.api.IDatatype;
import ca.uhn.fhir.model.api.ResourceReference;
public class Child extends BaseElement {
private String myReferenceType;
public boolean isBlock() {
return false;
}
public String getCardMaxForChildAnnotation() {
if (getCardMax().equals("*")) {
return "Child.MAX_UNLIMITED";
}else {
} else {
return getCardMax();
}
}
public String getReferenceType() {
return myReferenceType;
public List<String> getReferenceTypesForMultiple() {
ArrayList<String> retVal = new ArrayList<String>();
for (String next : getType()) {
retVal.add(next + "Dt");
}
return retVal;
}
public void setReferenceType(String theReferenceType) {
myReferenceType = theReferenceType;
public String getAnnotationType() {
return getSingleType();
}
public String getReferenceType() {
String retVal;
if (this.isResourceRef()) {
retVal = (ResourceReference.class.getSimpleName());
} else if (this.getType().size() == 1) {
retVal = getSingleType();
} else {
if (this instanceof Extension && ((Extension) this).getChildExtensions().size() > 0) {
retVal = ((Extension) this).getNameType();
} else {
retVal = IDatatype.class.getSimpleName();
}
}
if (this.isRepeatable()) {
retVal = ("List<" + retVal + ">");
}
return retVal;
}
protected String getSingleType() {
String retVal;
String elemName = this.getType().get(0);
elemName = elemName.substring(0, 1).toUpperCase() + elemName.substring(1);
if (this instanceof ResourceBlock) {
retVal = (elemName);
} else {
retVal = (elemName + "Dt");
}
return retVal;
}
public boolean isRepeatable() {
return "1".equals(getCardMax()) == false;
}
public String getVariableName() {
String elementName = getMethodName();
return "my" + elementName;
@ -32,7 +76,7 @@ public class Child extends BaseElement {
public String getMethodName() {
String elementName = getElementNameSimplified();
elementName = elementName.substring(0,1).toUpperCase() + elementName.substring(1);
elementName = elementName.substring(0, 1).toUpperCase() + elementName.substring(1);
return elementName;
}
@ -47,5 +91,4 @@ public class Child extends BaseElement {
return elementName;
}
}

View File

@ -1,84 +1,108 @@
package ca.uhn.fhir.starter.model;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import ca.uhn.fhir.model.api.IDatatype;
import org.apache.commons.lang3.StringUtils;
public class Extension {
public class Extension extends Child {
private List<Extension> myChildExtensions;
private Class<? extends IDatatype> myDatatype;
private String myName;
private String myUrl;
public Extension() {
super();
}
public boolean isHasDatatype() {
return myDatatype != null;
public List<Extension> getChildExtensionsWithChildren() {
ArrayList<Extension> retVal = new ArrayList<Extension>();
for (Extension next : getChildExtensions()) {
if (next.getChildExtensions().size() > 0) {
retVal.add(next);
}
}
return retVal;
}
public String getDatatypeSimpleName() {
return myDatatype.getSimpleName();
}
public String getNameType() {
return getName().substring(0, 1).toUpperCase()+getName().substring(1);
}
public Extension(String theName, String theUrl, Class<? extends IDatatype> theDatatype) {
setName(theName);
setUrl(theUrl);
setDatatype(theDatatype);
}
public Extension(String theName, String theUrl, Extension... theChildExtensions) {
setName(theName);
setUrl(theUrl);
setCardMin("0");
setCardMax("*");
if (theChildExtensions != null) {
setChildExtensions(Arrays.asList(theChildExtensions));
}
}
public Extension(String theName, String theUrl, String theDatatype) {
setName(theName);
setUrl(theUrl);
setTypeFromString(theDatatype);
setCardMin("0");
setCardMax("*");
}
public List<Extension> getChildExtensions() {
if (myChildExtensions == null) {
myChildExtensions = new ArrayList<Extension>();
}
return myChildExtensions;
}
public Class<? extends IDatatype> getDatatype() {
return myDatatype;
}
public String getName() {
return myName;
public String getNameType() {
return getName().substring(0, 1).toUpperCase() + getName().substring(1);
}
public String getUrl() {
return myUrl;
}
public boolean isHasChildExtensions() {
return getChildExtensions().size() > 0;
}
public void setChildExtensions(List<Extension> theChildExtensions) {
if (theChildExtensions != null && theChildExtensions.size() > 0 && myDatatype != null) {
if (theChildExtensions != null && theChildExtensions.size() > 0 && getType().size() > 0) {
throw new IllegalArgumentException("Extension may not have a datatype AND child extensions");
}
myChildExtensions = theChildExtensions;
}
public void setDatatype(Class<? extends IDatatype> theDatatype) {
if (myChildExtensions != null && myChildExtensions.size() > 0 && theDatatype != null) {
throw new IllegalArgumentException("Extension may not have a datatype AND child extensions");
@Override
public void setElementName(String theName) {
super.setElementName(theName);
if (getName() == null) {
super.setName(theName);
}
myDatatype = theDatatype;
}
@Override
public void setName(String theName) {
// TODO: validate that this is a valid name (no punctuation, spaces,
// etc.)
myName = theName;
super.setName(theName);
if (getElementName() == null) {
super.setElementName(theName);
}
}
@Override
public void setTypeFromString(String theType) {
if (myChildExtensions != null && myChildExtensions.size() > 0 && StringUtils.isNotBlank(theType)) {
throw new IllegalArgumentException("Extension may not have a datatype AND child extensions");
}
super.setTypeFromString(theType);
}
public void setUrl(String theUrl) {
myUrl = theUrl;
}
@Override
protected String getSingleType() {
if (isHasChildExtensions()) {
return getNameType();
}
return super.getSingleType();
}
}

View File

@ -5,5 +5,9 @@ public class ResourceBlock extends Child {
public String getClassName() {
return getElementName().substring(0,1).toUpperCase() + getElementName().substring(1);
}
public boolean isBlock() {
return true;
}
}

View File

@ -13,12 +13,14 @@
})
#elseif ($!child.hasMultipleTypes)
@Child(name="${child.elementNameSimplified}", order=${foreach.index}, min=${child.cardMin}, max=${child.cardMaxForChildAnnotation}, choice=@Choice(types= {
#foreach ($nextType in ${child.type})
#foreach ($nextType in ${child.referenceTypesForMultiple})
${nextType}.class,
#end
}))
#else
#elseif ($!child.block)
@Child(name="${child.elementNameSimplified}", order=${foreach.index}, min=${child.cardMin}, max=${child.cardMaxForChildAnnotation})
#else
@Child(name="${child.elementNameSimplified}", type=${child.annotationType}.class, order=${foreach.index}, min=${child.cardMin}, max=${child.cardMaxForChildAnnotation})
#end
private ${child.referenceType} ${child.variableName};
@ -65,8 +67,9 @@
#macro ( childExtensionFields $childExtensionTypes )
#foreach ( $extensionType in $childExtensionTypes )
@Child()
private ${extensionType.nameType} my${extensionType.nameType};
@Child(name="$extensionType.name", type=${extensionType.annotationType}.class, order=${foreach.index}, min=${extensionType.cardMin}, max=${extensionType.cardMaxForChildAnnotation})
@Extension(url="${extensionType.url}")
private ${extensionType.referenceType} ${extensionType.variableName};
#end
#end
@ -78,32 +81,24 @@
#macro ( childExtensionTypes $childExtensionTypes )
#foreach ( $extensionType in $childExtensionTypes )
@ExtensionBlock(url="${extensionType.url}")
public class ${extensionType.nameType} implements IExtension {
#if ( $extensionType.hasChildExtensions )
@Block(name="${extensionType.name}")
public static class ${extensionType.nameType} implements IExtension {
#if(${extensionType.hasDatatype})
@Child(name="value", order=0)
private ${extensionType.datatypeSimpleName} myValue;
#foreach ( $childExtensionSubtype in $extensionType.childExtensions )
@Child(name="$childExtensionSubtype.name", type=${childExtensionSubtype.annotationType}.class, order=${foreach.index}, min=${childExtensionSubtype.cardMin}, max=${childExtensionSubtype.cardMaxForChildAnnotation})
@Extension(url="${childExtensionSubtype.url}")
private ${childExtensionSubtype.referenceType} ${childExtensionSubtype.variableName};
/**
* Gets the value
*/
public ${extensionType.datatypeSimpleName} getValue() {
return myValue;
}
/**
* Sets the value
*/
public void setValue(${extensionType.datatypeSimpleName} theValue) {
myValue = theValue;
}
#else
#end
}
#foreach ( $extensionSubType in $extensionTypes.childExtensionsWithChildren )
#childExtensionTypes( $extensionSubType )
#end
#end
#end
#end