XML parser finally almost working

This commit is contained in:
jamesagnew 2014-02-19 17:33:46 -05:00
parent 5296e8121c
commit d097553f11
16 changed files with 526 additions and 132 deletions

View File

@ -1,59 +1,56 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="src" path="src/test/java" output="target/test-classes" including="**/*.java"/>
<classpathentry kind="src" path="src/test/resources" output="target/test-classes" excluding="**/*.java"/>
<classpathentry kind="src" path="src/main/java" including="**/*.java"/>
<classpathentry kind="output" path="target/classes"/>
<classpathentry kind="var" path="M2_REPO/javax/xml/stream/stax-api/1.0-2/stax-api-1.0-2.jar" sourcepath="M2_REPO/javax/xml/stream/stax-api/1.0-2/stax-api-1.0-2-sources.jar"/>
<classpathentry kind="var" path="M2_REPO/commons-codec/commons-codec/1.9/commons-codec-1.9.jar" sourcepath="M2_REPO/commons-codec/commons-codec/1.9/commons-codec-1.9-sources.jar">
<attributes>
<attribute value="jar:file:/Users/james/.m2/repository/commons-codec/commons-codec/1.9/commons-codec-1.9-javadoc.jar!/" name="javadoc_location"/>
</attributes>
</classpathentry>
<classpathentry kind="var" path="M2_REPO/commons-io/commons-io/1.3.2/commons-io-1.3.2.jar" sourcepath="M2_REPO/commons-io/commons-io/1.3.2/commons-io-1.3.2-sources.jar">
<attributes>
<attribute value="jar:file:/Users/james/.m2/repository/commons-io/commons-io/1.3.2/commons-io-1.3.2-javadoc.jar!/" name="javadoc_location"/>
</attributes>
</classpathentry>
<classpathentry kind="var" path="M2_REPO/org/apache/commons/commons-lang3/3.2.1/commons-lang3-3.2.1.jar" sourcepath="M2_REPO/org/apache/commons/commons-lang3/3.2.1/commons-lang3-3.2.1-sources.jar">
<attributes>
<attribute value="jar:file:/Users/james/.m2/repository/org/apache/commons/commons-lang3/3.2.1/commons-lang3-3.2.1-javadoc.jar!/" name="javadoc_location"/>
</attributes>
</classpathentry>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
<classpathentry kind="var" path="M2_REPO/com/google/code/gson/gson/2.2.4/gson-2.2.4.jar" sourcepath="M2_REPO/com/google/code/gson/gson/2.2.4/gson-2.2.4-sources.jar">
<attributes>
<attribute value="jar:file:/Users/james/.m2/repository/com/google/code/gson/gson/2.2.4/gson-2.2.4-javadoc.jar!/" name="javadoc_location"/>
<attribute value="jar:file:/home/t3903uhn/.m2/repository/com/google/code/gson/gson/2.2.4/gson-2.2.4-javadoc.jar!/" name="javadoc_location"/>
</attributes>
</classpathentry>
<classpathentry kind="var" path="M2_REPO/org/hamcrest/hamcrest-core/1.3/hamcrest-core-1.3.jar" sourcepath="M2_REPO/org/hamcrest/hamcrest-core/1.3/hamcrest-core-1.3-sources.jar">
<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/hamcrest/hamcrest-core/1.3/hamcrest-core-1.3-javadoc.jar!/" name="javadoc_location"/>
<attribute value="jar:file:/home/t3903uhn/.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/junit/junit/4.11/junit-4.11.jar" sourcepath="M2_REPO/junit/junit/4.11/junit-4.11-sources.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/org/apache/commons/commons-lang3/3.2.1/commons-lang3-3.2.1.jar" sourcepath="M2_REPO/org/apache/commons/commons-lang3/3.2.1/commons-lang3-3.2.1-sources.jar">
<attributes>
<attribute value="jar:file:/Users/james/.m2/repository/junit/junit/4.11/junit-4.11-javadoc.jar!/" name="javadoc_location"/>
<attribute value="jar:file:/home/t3903uhn/.m2/repository/org/apache/commons/commons-lang3/3.2.1/commons-lang3-3.2.1-javadoc.jar!/" name="javadoc_location"/>
</attributes>
</classpathentry>
<classpathentry kind="var" path="M2_REPO/commons-codec/commons-codec/1.9/commons-codec-1.9.jar" sourcepath="M2_REPO/commons-codec/commons-codec/1.9/commons-codec-1.9-sources.jar"/>
<classpathentry kind="var" path="M2_REPO/org/slf4j/slf4j-api/1.7.6/slf4j-api-1.7.6.jar" sourcepath="M2_REPO/org/slf4j/slf4j-api/1.7.6/slf4j-api-1.7.6-sources.jar">
<attributes>
<attribute value="jar:file:/home/t3903uhn/.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/ch/qos/logback/logback-classic/1.1.1/logback-classic-1.1.1.jar" sourcepath="M2_REPO/ch/qos/logback/logback-classic/1.1.1/logback-classic-1.1.1-sources.jar">
<attributes>
<attribute value="jar:file:/Users/james/.m2/repository/ch/qos/logback/logback-classic/1.1.1/logback-classic-1.1.1-javadoc.jar!/" name="javadoc_location"/>
<attribute value="jar:file:/home/t3903uhn/.m2/repository/ch/qos/logback/logback-classic/1.1.1/logback-classic-1.1.1-javadoc.jar!/" name="javadoc_location"/>
</attributes>
</classpathentry>
<classpathentry kind="var" path="M2_REPO/ch/qos/logback/logback-core/1.1.1/logback-core-1.1.1.jar" sourcepath="M2_REPO/ch/qos/logback/logback-core/1.1.1/logback-core-1.1.1-sources.jar">
<attributes>
<attribute value="jar:file:/Users/james/.m2/repository/ch/qos/logback/logback-core/1.1.1/logback-core-1.1.1-javadoc.jar!/" name="javadoc_location"/>
<attribute value="jar:file:/home/t3903uhn/.m2/repository/ch/qos/logback/logback-core/1.1.1/logback-core-1.1.1-javadoc.jar!/" name="javadoc_location"/>
</attributes>
</classpathentry>
<classpathentry kind="var" path="M2_REPO/org/slf4j/slf4j-api/1.7.6/slf4j-api-1.7.6.jar" sourcepath="M2_REPO/org/slf4j/slf4j-api/1.7.6/slf4j-api-1.7.6-sources.jar">
<classpathentry kind="var" path="M2_REPO/junit/junit/4.11/junit-4.11.jar" sourcepath="M2_REPO/junit/junit/4.11/junit-4.11-sources.jar">
<attributes>
<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"/>
<attribute value="jar:file:/home/t3903uhn/.m2/repository/junit/junit/4.11/junit-4.11-javadoc.jar!/" name="javadoc_location"/>
</attributes>
</classpathentry>
<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/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">
<classpathentry kind="var" path="M2_REPO/org/hamcrest/hamcrest-core/1.3/hamcrest-core-1.3.jar" sourcepath="M2_REPO/org/hamcrest/hamcrest-core/1.3/hamcrest-core-1.3-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"/>
<attribute value="jar:file:/home/t3903uhn/.m2/repository/org/hamcrest/hamcrest-core/1.3/hamcrest-core-1.3-javadoc.jar!/" name="javadoc_location"/>
</attributes>
</classpathentry>
<classpathentry kind="var" path="M2_REPO/commons-io/commons-io/1.3.2/commons-io-1.3.2.jar" sourcepath="M2_REPO/commons-io/commons-io/1.3.2/commons-io-1.3.2-sources.jar">
<attributes>
<attribute value="jar:file:/home/t3903uhn/.m2/repository/commons-io/commons-io/1.3.2/commons-io-1.3.2-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

@ -1,3 +1,4 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>hapi-fhir-base</name>
<comment>NO_M2ECLIPSE_SUPPORT: Project files created with the maven-eclipse-plugin are not supported in M2Eclipse.</comment>

View File

@ -1,10 +1,11 @@
package ca.uhn.fhir.context;
import static org.apache.commons.lang3.StringUtils.*;
import static org.apache.commons.lang3.StringUtils.isBlank;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
@ -44,50 +45,22 @@ public abstract class BaseRuntimeChildDefinition {
// TODO: handle lists (max>0), and maybe max=0?
if (myMax == 1) {
Class<?> declaringClass = myField.getDeclaringClass();
Class<?> targetReturnType = myField.getType();
final Class<?> targetReturnType = myField.getType();
try {
final Method accessor = BeanUtils.findAccessor(declaringClass, targetReturnType, myElementName);
final Method mutator = BeanUtils.findMutator(declaringClass, targetReturnType, myElementName);
myAccessor = new IAccessor() {
@Override
public List<Object> getValues(Object theTarget) {
try {
return Collections.singletonList(accessor.invoke(theTarget));
} catch (IllegalAccessException e) {
throw new ConfigurationException("Failed to get value", e);
} catch (IllegalArgumentException e) {
throw new ConfigurationException("Failed to get value", e);
} catch (InvocationTargetException e) {
throw new ConfigurationException("Failed to get value", e);
if (List.class.isAssignableFrom(targetReturnType)) {
myAccessor = new ListAccessor(accessor);
myMutator = new ListMutator(mutator);
}else {
myAccessor = new PlainAccessor(accessor);
myMutator = new PlainMutator(targetReturnType, mutator);
}
}
};
myMutator = new IMutator() {
@Override
public void addValue(Object theTarget, Object theValue) {
try {
mutator.invoke(theTarget, theValue);
} catch (IllegalAccessException e) {
throw new ConfigurationException("Failed to get value", e);
} catch (IllegalArgumentException e) {
throw new ConfigurationException("Failed to get value", e);
} catch (InvocationTargetException e) {
throw new ConfigurationException("Failed to get value", e);
}
}
};
} catch (NoSuchFieldException e) {
throw new ConfigurationException(e);
}
} else {
// replace this with an implementation
myAccessor = null;
myMutator = null;
}
}
@ -121,6 +94,101 @@ public abstract class BaseRuntimeChildDefinition {
abstract void sealAndInitialize(Map<Class<? extends IElement>, BaseRuntimeElementDefinition<?>> theClassToElementDefinitions);
private final class ListMutator implements IMutator {
private final Method myMutator;
private ListMutator(Method theMutator) {
myMutator = theMutator;
}
@Override
public void addValue(Object theTarget, Object theValue) {
List<Object> existingList = myAccessor.getValues(theTarget);
if (existingList == null) {
existingList = new ArrayList<Object>();
try {
myMutator.invoke(theTarget, existingList);
} catch (IllegalAccessException e) {
throw new ConfigurationException("Failed to get value", e);
} catch (IllegalArgumentException e) {
throw new ConfigurationException("Failed to get value", e);
} catch (InvocationTargetException e) {
throw new ConfigurationException("Failed to get value", e);
}
}
existingList.add(theValue);
}
}
private final class ListAccessor implements IAccessor {
private final Method myAccessor;
private ListAccessor(Method theAccessor) {
myAccessor = theAccessor;
}
@SuppressWarnings("unchecked")
@Override
public List<Object> getValues(Object theTarget) {
try {
return (List<Object>) myAccessor.invoke(theTarget);
} catch (IllegalAccessException e) {
throw new ConfigurationException("Failed to get value", e);
} catch (IllegalArgumentException e) {
throw new ConfigurationException("Failed to get value", e);
} catch (InvocationTargetException e) {
throw new ConfigurationException("Failed to get value", e);
}
}
}
private final class PlainMutator implements IMutator {
private final Class<?> myTargetReturnType;
private final Method myMutator;
private PlainMutator(Class<?> theTargetReturnType, Method theMutator) {
myTargetReturnType = theTargetReturnType;
myMutator = theMutator;
}
@Override
public void addValue(Object theTarget, Object theValue) {
try {
if (theValue != null && !myTargetReturnType.isAssignableFrom(theValue.getClass())) {
throw new ConfigurationException("Value for field " + myElementName + " expects type " + myTargetReturnType + " but got " + theValue.getClass());
}
myMutator.invoke(theTarget, theValue);
} catch (IllegalAccessException e) {
throw new ConfigurationException("Failed to get value", e);
} catch (IllegalArgumentException e) {
throw new ConfigurationException("Failed to get value", e);
} catch (InvocationTargetException e) {
throw new ConfigurationException("Failed to get value", e);
}
}
}
private final class PlainAccessor implements IAccessor {
private final Method myAccessor;
private PlainAccessor(Method theAccessor) {
myAccessor = theAccessor;
}
@Override
public List<Object> getValues(Object theTarget) {
try {
return Collections.singletonList(myAccessor.invoke(theTarget));
} catch (IllegalAccessException e) {
throw new ConfigurationException("Failed to get value", e);
} catch (IllegalArgumentException e) {
throw new ConfigurationException("Failed to get value", e);
} catch (InvocationTargetException e) {
throw new ConfigurationException("Failed to get value", e);
}
}
}
public interface IMutator {
void addValue(Object theTarget, Object theValue);
}

View File

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

View File

@ -1,12 +1,11 @@
package ca.uhn.fhir.context;
import static org.apache.commons.lang3.StringUtils.*;
import static org.apache.commons.lang3.StringUtils.isBlank;
import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
@ -14,7 +13,6 @@ import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.Stack;
import java.util.TreeMap;
import ca.uhn.fhir.model.api.CodeableConceptElement;
@ -88,7 +86,8 @@ class ModelScanner {
ResourceDef resourceDefinition = theClass.getAnnotation(ResourceDef.class);
if (resourceDefinition != null) {
if (!IResource.class.isAssignableFrom(theClass)) {
throw new ConfigurationException("Resource type contains a @" + ResourceDef.class.getSimpleName() + " annotation but does not implement " + IResource.class.getCanonicalName() + ": " + theClass.getCanonicalName());
throw new ConfigurationException("Resource type contains a @" + ResourceDef.class.getSimpleName() + " annotation but does not implement " + IResource.class.getCanonicalName() + ": "
+ theClass.getCanonicalName());
}
@SuppressWarnings("unchecked")
Class<? extends IResource> resClass = (Class<? extends IResource>) theClass;
@ -106,7 +105,8 @@ class ModelScanner {
Class<? extends IPrimitiveDatatype> resClass = (Class<? extends IPrimitiveDatatype>) theClass;
return scanPrimitiveDatatype(resClass, datatypeDefinition);
} else {
throw new ConfigurationException("Resource type contains a @" + DatatypeDef.class.getSimpleName() + " annotation but does not implement " + IDatatype.class.getCanonicalName() + ": " + theClass.getCanonicalName());
throw new ConfigurationException("Resource type contains a @" + DatatypeDef.class.getSimpleName() + " annotation but does not implement " + IDatatype.class.getCanonicalName() + ": "
+ theClass.getCanonicalName());
}
}
@ -117,11 +117,13 @@ class ModelScanner {
Class<? extends ICodeEnum> resClass = (Class<? extends ICodeEnum>) theClass;
return scanCodeTable(resClass, codeTableDefinition);
} else {
throw new ConfigurationException("Resource type contains a @" + CodeTableDef.class.getSimpleName() + " annotation but does not implement " + ICodeEnum.class.getCanonicalName() + ": " + theClass.getCanonicalName());
throw new ConfigurationException("Resource type contains a @" + CodeTableDef.class.getSimpleName() + " annotation but does not implement " + ICodeEnum.class.getCanonicalName() + ": "
+ theClass.getCanonicalName());
}
}
throw new ConfigurationException("Resource type does not contain a @" + ResourceDef.class.getSimpleName() + " annotation or a @" + DatatypeDef.class.getSimpleName() + " annotation: " + theClass.getCanonicalName());
throw new ConfigurationException("Resource type does not contain a @" + ResourceDef.class.getSimpleName() + " annotation or a @" + DatatypeDef.class.getSimpleName() + " annotation: "
+ theClass.getCanonicalName());
}
private String scanCompositeDatatype(Class<? extends ICompositeDatatype> theClass, DatatypeDef theDatatypeDefinition) {
@ -164,7 +166,8 @@ class ModelScanner {
if (myNameToResourceDefinitions.containsKey(resourceName)) {
if (!myNameToResourceDefinitions.get(resourceName).getImplementingClass().equals(theClass)) {
throw new ConfigurationException("Detected duplicate element name '" + resourceName + "' in types '" + theClass.getCanonicalName() + "' and '" + myNameToResourceDefinitions.get(resourceName).getImplementingClass() + "'");
throw new ConfigurationException("Detected duplicate element name '" + resourceName + "' in types '" + theClass.getCanonicalName() + "' and '"
+ myNameToResourceDefinitions.get(resourceName).getImplementingClass() + "'");
}
return resourceName;
}
@ -189,10 +192,10 @@ class ModelScanner {
classes.push(current);
if (ICompositeElement.class.isAssignableFrom(current.getSuperclass())) {
current = (Class<? extends ICompositeElement>) current.getSuperclass();
}else {
} else {
current = null;
}
}while (current != null);
} while (current != null);
for (Class<? extends ICompositeElement> next : classes) {
scanCompositeElementForChildren(next, theDefinition, elementNames, orderToElementDef);
@ -202,14 +205,15 @@ class ModelScanner {
BaseRuntimeChildDefinition elementDef = orderToElementDef.remove(orderToElementDef.firstKey());
if (elementDef.getElementName().equals("identifier")) {
orderToElementDef.put(theIdentifierOrder, elementDef);
}else {
} else {
throw new ConfigurationException("Don't know how to handle element: " + elementDef.getElementName());
}
}
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)");
throw new ConfigurationException("Type '" + theClass.getCanonicalName() + "' does not have a child with order " + i
+ " (in other words, there are gaps between specified child orders)");
}
BaseRuntimeChildDefinition next = orderToElementDef.get(i);
theDefinition.addChild(next);
@ -218,7 +222,8 @@ class ModelScanner {
}
@SuppressWarnings("unchecked")
private void scanCompositeElementForChildren(Class<? extends ICompositeElement> theClass, BaseRuntimeElementCompositeDefinition<?> theDefinition, Set<String> elementNames, TreeMap<Integer, BaseRuntimeChildDefinition> orderToElementDef) {
private void scanCompositeElementForChildren(Class<? extends ICompositeElement> theClass, BaseRuntimeElementCompositeDefinition<?> theDefinition, Set<String> elementNames,
TreeMap<Integer, BaseRuntimeChildDefinition> orderToElementDef) {
for (Field next : theClass.getDeclaredFields()) {
Narrative hasNarrative = next.getAnnotation(Narrative.class);
@ -230,11 +235,12 @@ class ModelScanner {
throw new ConfigurationException("Failed to find narrative field", e);
}
theDefinition.addChild(def);
continue;
}
Child element = next.getAnnotation(Child.class);
if (element == null) {
ourLog.debug("Ignoring non-type field: " + next.getName());
ourLog.debug("Ignoring non-type field '" + next.getName() + "' on target type: " + theClass);
continue;
}
@ -275,7 +281,8 @@ class ModelScanner {
* Child is a resource reference
*/
if (resRefAnnotation == null) {
throw new ConfigurationException("Field '" + elementName + "' in type '" + theClass.getCanonicalName() + "' is a resource reference but does not have a @" + ChildResource.class.getSimpleName() + " annotation");
throw new ConfigurationException("Field '" + elementName + "' in type '" + theClass.getCanonicalName() + "' is a resource reference but does not have a @"
+ ChildResource.class.getSimpleName() + " annotation");
}
Class<? extends IResource>[] refType = resRefAnnotation.types();
@ -286,7 +293,8 @@ class ModelScanner {
} else {
if (resRefAnnotation != null) {
throw new ConfigurationException("Field '" + elementName + "' in type '" + theClass.getCanonicalName() + "' is not a resource reference but has a @" + ChildResource.class.getSimpleName() + " annotation");
throw new ConfigurationException("Field '" + elementName + "' in type '" + theClass.getCanonicalName() + "' is not a resource reference but has a @"
+ ChildResource.class.getSimpleName() + " annotation");
}
Class<? extends IDatatype> nextDatatype;
@ -294,18 +302,24 @@ class ModelScanner {
if (IDatatype.class.isAssignableFrom(next.getType())) {
nextDatatype = (Class<? extends IDatatype>) next.getType();
} else {
if (Collection.class.isAssignableFrom(next.getType())) {
Class<?> type = (Class<?>) ((ParameterizedType) next.getType().getGenericSuperclass()).getActualTypeArguments()[0];
if (IDatatype.class.isAssignableFrom(type)) {
nextDatatype=(Class<? extends IDatatype>) type;
}else {
throw new ConfigurationException("Field '" + elementName + "' in type '" + theClass.getCanonicalName() + "' is not a resource reference and is not an instance of type " + IDatatype.class.getName());
}
}else {
throw new ConfigurationException("Field '" + elementName + "' in type '" + theClass.getCanonicalName() + "' is not a resource reference and is not an instance of type " + IDatatype.class.getName());
}
}
if (List.class.isAssignableFrom(next.getType())) {
Class<?> type = getGenericCollectionTypeOfField(next);
if (IDatatype.class.isAssignableFrom(type)) {
nextDatatype = (Class<? extends IDatatype>) type;
} else {
throw new ConfigurationException("Field '" + elementName + "' in type '" + theClass.getCanonicalName() + "' is not a resource reference and is not an instance of type "
+ IDatatype.class.getName());
}
} else {
/* TODO: detect when someone has used a different collection (set, etc.) and
* give a nice error that indicates that they need to use List..
*/
throw new ConfigurationException("Field '" + elementName + "' in type '" + theClass.getCanonicalName() + "' is not a resource reference and is not an instance of type "
+ IDatatype.class.getName());
}
}
myScanAlso.add(nextDatatype);
@ -319,7 +333,8 @@ class ModelScanner {
CodeableConceptElement concept = next.getAnnotation(CodeableConceptElement.class);
if (concept != null) {
if (!ICodedDatatype.class.isAssignableFrom(nextDatatype)) {
throw new ConfigurationException("Field '" + elementName + "' in type '" + theClass.getCanonicalName() + "' is marked as @" + CodeableConceptElement.class.getCanonicalName() + " but type is not a subtype of " + ICodedDatatype.class.getName());
throw new ConfigurationException("Field '" + elementName + "' in type '" + theClass.getCanonicalName() + "' is marked as @" + CodeableConceptElement.class.getCanonicalName()
+ " but type is not a subtype of " + ICodedDatatype.class.getName());
} else {
Class<? extends ICodeEnum> type = concept.type();
myScanAlsoCodeTable.add(type);
@ -350,6 +365,19 @@ class ModelScanner {
}
}
private static Class<?> getGenericCollectionTypeOfField(Field next) {
// Type genericSuperclass = next.getType().getGenericSuperclass();
Class<?> type;
// if (genericSuperclass == null) {
ParameterizedType collectionType = (ParameterizedType) next.getGenericType();
type = (Class<?>) collectionType.getActualTypeArguments()[0];
// }else {
// Type[] actualTypeArguments = ((ParameterizedType) genericSuperclass).getActualTypeArguments();
// type = (Class<?>) actualTypeArguments[0];
// }
return type;
}
private String scanCodeTable(Class<? extends ICodeEnum> theCodeType, CodeTableDef theCodeTableDefinition) {
return null; // TODO: implement
}

View File

@ -11,40 +11,24 @@ import ca.uhn.fhir.model.api.IResource;
public class RuntimeChildResourceDefinition extends BaseRuntimeChildDefinition {
private static final String REFERENCE = "reference";
private String myResourceName;
private Set<String> myValidChildNames;
private List<Class<? extends IResource>> myChildTypes;
public RuntimeChildResourceDefinition(Field theField, String theElementName, int theMin, int theMax, List<Class<? extends IResource>> theChildTypes) {
super(theField, theMin,theMax, theElementName);
myChildTypes = theChildTypes;
}
public String getResourceName() {
return myResourceName;
super(theField, theMin, theMax, theElementName);
}
@Override
public Set<String> getValidChildNames() {
return Collections.singleton(REFERENCE);
return Collections.singleton(getElementName());
}
@Override
public BaseRuntimeElementDefinition<?> getChildByName(String theName) {
if (REFERENCE.equals(theName)) {
return null; // TODO: implement
}
return null;
return new RuntimeResourceReferenceDefinition(null, null);
}
@Override
void sealAndInitialize(Map<Class<? extends IElement>, BaseRuntimeElementDefinition<?>> theClassToElementDefinitions) {
// TODO Auto-generated method stub
// nothing
}
}

View File

@ -0,0 +1,25 @@
package ca.uhn.fhir.context;
import java.util.Map;
import ca.uhn.fhir.model.api.IElement;
import ca.uhn.fhir.model.api.IResource;
public class RuntimeResourceReferenceDefinition extends BaseRuntimeElementDefinition<IResource> {
public RuntimeResourceReferenceDefinition(String theName, Class<? extends IResource> theImplementingClass) {
super(theName, theImplementingClass);
}
@Override
void sealAndInitialize(Map<Class<? extends IElement>, BaseRuntimeElementDefinition<?>> theClassToElementDefinitions) {
// TODO Auto-generated method stub
}
@Override
public ca.uhn.fhir.context.BaseRuntimeElementDefinition.ChildTypeEnum getChildType() {
return ChildTypeEnum.RESOURCE_REF;
}
}

View File

@ -1,6 +1,24 @@
package ca.uhn.fhir.model.api;
public class ResourceReference /* <T extends BaseResource> */{
public class ResourceReference /*<T extends BaseResource>*/ {
private String myDisplay;
private String myReference;
public String getDisplay() {
return myDisplay;
}
public String getReference() {
return myReference;
}
public void setDisplay(String theDisplay) {
myDisplay = theDisplay;
}
public void setReference(String theReference) {
myReference = theReference;
}
}

View File

@ -15,6 +15,11 @@ public @interface Child {
*/
int ORDER_UNKNOWN = -1;
/**
* COnstant value to supply for {@link #max()} to indicate '*' (no maximum)
*/
int MAX_UNLIMITED = -1;
String name();
int order();

View File

@ -9,10 +9,10 @@ import ca.uhn.fhir.model.api.annotation.Description;
public class AttachmentDt extends BaseCompositeDatatype {
@Child(name="contentType", order=0, min=1)
private CodeDt myContentType;
private CodeDt<?> myContentType;
@Child(name="language", order=1)
private CodeDt myLanguage;
private CodeDt<?> myLanguage;
@Child(name="data", order=2)
private Base64BinaryDt myData;
@ -27,8 +27,66 @@ public class AttachmentDt extends BaseCompositeDatatype {
@Description("Hash of the data (sha-1, base64ed )")
private Base64BinaryDt myHash;
@Child(name="title", order=5)
@Child(name="title", order=6)
@Description("Label to display in place of the data")
private StringDt myLabel;
private StringDt myTitle;
public CodeDt<?> getContentType() {
return myContentType;
}
public void setContentType(CodeDt<?> theContentType) {
myContentType = theContentType;
}
public CodeDt<?> getLanguage() {
return myLanguage;
}
public void setLanguage(CodeDt<?> theLanguage) {
myLanguage = theLanguage;
}
public Base64BinaryDt getData() {
return myData;
}
public void setData(Base64BinaryDt theData) {
myData = theData;
}
public UriDt getUrl() {
return myUrl;
}
public void setUrl(UriDt theUrl) {
myUrl = theUrl;
}
public Base64BinaryDt getHash() {
return myHash;
}
public void setHash(Base64BinaryDt theHash) {
myHash = theHash;
}
public StringDt getTitle() {
return myTitle;
}
public void setTitle(StringDt theTitle) {
myTitle = theTitle;
}
public IntegerDt getSize() {
return mySize;
}
public void setSize(IntegerDt theSize) {
mySize = theSize;
}
}

View File

@ -10,9 +10,28 @@ import ca.uhn.fhir.model.api.annotation.DatatypeDef;
@DatatypeDef(name="CodeableConcept")
public class CodeableConceptDt<T extends ICodeEnum> extends BaseCompositeDatatype implements ICodedDatatype {
@Child(name="coding", order=0)
@Child(name="coding", order=0, min=0, max=Child.MAX_UNLIMITED)
private List<CodingDt> myCoding;
@Child(name="text",order=1)
private StringDt myText;
public List<CodingDt> getCoding() {
return myCoding;
}
public void setCoding(List<CodingDt> theCoding) {
myCoding = theCoding;
}
public StringDt getText() {
return myText;
}
public void setText(StringDt theText) {
myText = theText;
}
}

View File

@ -26,8 +26,58 @@ public class CodingDt extends BaseCompositeDatatype {
@Child(name="primary", order=4)
private BooleanDt myPrimary;
@Child(name="valueSet", order=5)
@Child(name="assigner", order=5)
@ChildResource(types= {ValueSet.class})
private ResourceReference myAssigner;
public UriDt getSystem() {
return mySystem;
}
public void setSystem(UriDt theSystem) {
mySystem = theSystem;
}
public StringDt getVersion() {
return myVersion;
}
public void setVersion(StringDt theVersion) {
myVersion = theVersion;
}
public CodeDt<?> getCode() {
return myCode;
}
public void setCode(CodeDt<?> theCode) {
myCode = theCode;
}
public StringDt getDisplay() {
return myDisplay;
}
public void setDisplay(StringDt theDisplay) {
myDisplay = theDisplay;
}
public BooleanDt getPrimary() {
return myPrimary;
}
public void setPrimary(BooleanDt thePrimary) {
myPrimary = thePrimary;
}
public ResourceReference getAssigner() {
return myAssigner;
}
public void setAssigner(ResourceReference theAssigner) {
myAssigner = theAssigner;
}
}

View File

@ -15,4 +15,22 @@ public class RatioDt extends BaseCompositeDatatype {
@Child(name="denominator", order=1)
@Constraint(coRequirements= {"numerator"})
private QuantityDt myDenominator;
public QuantityDt getNumerator() {
return myNumerator;
}
public void setNumerator(QuantityDt theNumerator) {
myNumerator = theNumerator;
}
public QuantityDt getDenominator() {
return myDenominator;
}
public void setDenominator(QuantityDt theDenominator) {
myDenominator = theDenominator;
}
}

View File

@ -29,4 +29,62 @@ public class SampledDataDt extends BaseCompositeDatatype {
@Child(name="data", order=6, min=1)
@Description("Decimal values with spaces, or \"E\" | \"U\" | \"L\"")
private StringDt myData;
public QuantityDt getOrigin() {
return myOrigin;
}
public void setOrigin(QuantityDt theOrigin) {
myOrigin = theOrigin;
}
public DecimalDt getPeriod() {
return myPeriod;
}
public void setPeriod(DecimalDt thePeriod) {
myPeriod = thePeriod;
}
public DecimalDt getFactor() {
return myFactor;
}
public void setFactor(DecimalDt theFactor) {
myFactor = theFactor;
}
public DecimalDt getLowerLimit() {
return myLowerLimit;
}
public void setLowerLimit(DecimalDt theLowerLimit) {
myLowerLimit = theLowerLimit;
}
public DecimalDt getUpperLimit() {
return myUpperLimit;
}
public void setUpperLimit(DecimalDt theUpperLimit) {
myUpperLimit = theUpperLimit;
}
public IntegerDt getDimensions() {
return myDimensions;
}
public void setDimensions(IntegerDt theDimensions) {
myDimensions = theDimensions;
}
public StringDt getData() {
return myData;
}
public void setData(StringDt theData) {
myData = theData;
}
}

View File

@ -6,14 +6,70 @@ import ca.uhn.fhir.context.BaseRuntimeElementDefinition;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.context.RuntimePrimitiveDatatypeDefinition;
import ca.uhn.fhir.context.RuntimeResourceDefinition;
import ca.uhn.fhir.model.api.BaseCompositeDatatype;
import ca.uhn.fhir.context.RuntimeResourceReferenceDefinition;
import ca.uhn.fhir.model.api.ICompositeDatatype;
import ca.uhn.fhir.model.api.ICompositeElement;
import ca.uhn.fhir.model.api.IPrimitiveDatatype;
import ca.uhn.fhir.model.api.IResource;
import ca.uhn.fhir.model.api.ResourceReference;
class ParserState {
private enum ResourceReferenceSubState {
INITIAL, REFERENCE, DISPLAY
}
private class ResourceReferenceState extends BaseState {
private ResourceReferenceSubState mySubState;
private RuntimeResourceReferenceDefinition myDefinition;
private ResourceReference myInstance;
public ResourceReferenceState(RuntimeResourceReferenceDefinition theDefinition, ResourceReference theInstance) {
myDefinition=theDefinition;
myInstance = theInstance;
mySubState = ResourceReferenceSubState.INITIAL;
}
@Override
public void attributeValue(String theValue) throws DataFormatException {
switch (mySubState) {
case DISPLAY:
myInstance.setDisplay(theValue);
break;
case INITIAL:
throw new DataFormatException("Unexpected attribute: "+theValue);
case REFERENCE:
myInstance.setReference(theValue);
break;
}
}
@Override
public void enteringNewElement(String theLocalPart) throws DataFormatException {
switch (mySubState) {
case INITIAL:
if ("display".equals(theLocalPart)) {
mySubState = ResourceReferenceSubState.DISPLAY;
break;
} else if ("reference".equals(theLocalPart)) {
mySubState = ResourceReferenceSubState.REFERENCE;
break;
}
// ...else fall through...
case DISPLAY:
case REFERENCE:
throw new DataFormatException("Unexpected element: "+theLocalPart);
}
}
@Override
public void endingElement(String theLocalPart) {
mySubState=ResourceReferenceSubState.INITIAL;
}
}
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(ParserState.class);
private FhirContext myContext;
@ -106,11 +162,17 @@ private abstract class BaseState {
push(newState);
break;
}
case RESOURCE: {
case RESOURCE_REF: {
RuntimeResourceReferenceDefinition resourceRefTarget = (RuntimeResourceReferenceDefinition) target;
ResourceReference newChildInstance = new ResourceReference();
child.getMutator().addValue(myInstance, newChildInstance);
ResourceReferenceState newState = new ResourceReferenceState(resourceRefTarget, newChildInstance);
push(newState);
break;
}
case RESOURCE:
default:
throw new DataFormatException("Illegal resource position");
throw new DataFormatException("Illegal resource position: " + target.getChildType());
}
}

View File

@ -7,6 +7,7 @@ import org.junit.Test;
import ca.uhn.fhir.context.ConfigurationException;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.model.api.IResource;
import ca.uhn.fhir.model.resource.Observation;
public class XmlParserTest {
@ -17,7 +18,9 @@ public class XmlParserTest {
FhirContext ctx = new FhirContext(Observation.class);
XmlParser p = new XmlParser(ctx);
p.parseResource(IOUtils.toString(XmlParserTest.class.getResourceAsStream("/observation-example-eeg.xml")));
IResource resource = p.parseResource(IOUtils.toString(XmlParserTest.class.getResourceAsStream("/observation-example-eeg.xml")));
System.out.println(resource);
}