Still not passing

This commit is contained in:
jamesagnew 2014-02-19 11:59:12 -05:00
parent 5e97109f4c
commit 9aa5e52911
35 changed files with 1205 additions and 199 deletions

View File

@ -1,55 +1,59 @@
<?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="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">
<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:/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/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:/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/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:/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/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:/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:/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/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:/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/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:/home/t3903uhn/.m2/repository/org/hamcrest/hamcrest-core/1.3/hamcrest-core-1.3-javadoc.jar!/" name="javadoc_location"/>
<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:/home/t3903uhn/.m2/repository/commons-io/commons-io/1.3.2/commons-io-1.3.2-javadoc.jar!/" name="javadoc_location"/>
<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="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"/>
</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">
<attributes>
<attribute value="jar:file:/Users/james/.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/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/junit/junit/4.11/junit-4.11-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"/>
</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"/>
</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">
<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"/>
</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">
<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="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.6"/>
</classpath>

View File

@ -1,4 +1,3 @@
<?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,5 +1,92 @@
#Sun Feb 16 17:15:18 EST 2014
org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6
eclipse.preferences.version=1
org.eclipse.jdt.core.compiler.source=1.6
org.eclipse.jdt.core.compiler.annotation.inheritNullAnnotations=disabled
org.eclipse.jdt.core.compiler.annotation.missingNonNullByDefaultAnnotation=ignore
org.eclipse.jdt.core.compiler.annotation.nonnull=org.eclipse.jdt.annotation.NonNull
org.eclipse.jdt.core.compiler.annotation.nonnullbydefault=org.eclipse.jdt.annotation.NonNullByDefault
org.eclipse.jdt.core.compiler.annotation.nullable=org.eclipse.jdt.annotation.Nullable
org.eclipse.jdt.core.compiler.annotation.nullanalysis=enabled
org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6
org.eclipse.jdt.core.compiler.compliance=1.6
org.eclipse.jdt.core.compiler.problem.annotationSuperInterface=warning
org.eclipse.jdt.core.compiler.problem.autoboxing=ignore
org.eclipse.jdt.core.compiler.problem.comparingIdentical=warning
org.eclipse.jdt.core.compiler.problem.deadCode=warning
org.eclipse.jdt.core.compiler.problem.deprecation=warning
org.eclipse.jdt.core.compiler.problem.deprecationInDeprecatedCode=disabled
org.eclipse.jdt.core.compiler.problem.deprecationWhenOverridingDeprecatedMethod=disabled
org.eclipse.jdt.core.compiler.problem.discouragedReference=warning
org.eclipse.jdt.core.compiler.problem.emptyStatement=warning
org.eclipse.jdt.core.compiler.problem.explicitlyClosedAutoCloseable=ignore
org.eclipse.jdt.core.compiler.problem.fallthroughCase=warning
org.eclipse.jdt.core.compiler.problem.fatalOptionalError=disabled
org.eclipse.jdt.core.compiler.problem.fieldHiding=warning
org.eclipse.jdt.core.compiler.problem.finalParameterBound=warning
org.eclipse.jdt.core.compiler.problem.finallyBlockNotCompletingNormally=warning
org.eclipse.jdt.core.compiler.problem.forbiddenReference=error
org.eclipse.jdt.core.compiler.problem.hiddenCatchBlock=warning
org.eclipse.jdt.core.compiler.problem.includeNullInfoFromAsserts=disabled
org.eclipse.jdt.core.compiler.problem.incompatibleNonInheritedInterfaceMethod=warning
org.eclipse.jdt.core.compiler.problem.incompleteEnumSwitch=warning
org.eclipse.jdt.core.compiler.problem.indirectStaticAccess=warning
org.eclipse.jdt.core.compiler.problem.localVariableHiding=warning
org.eclipse.jdt.core.compiler.problem.methodWithConstructorName=warning
org.eclipse.jdt.core.compiler.problem.missingDefaultCase=ignore
org.eclipse.jdt.core.compiler.problem.missingDeprecatedAnnotation=ignore
org.eclipse.jdt.core.compiler.problem.missingEnumCaseDespiteDefault=disabled
org.eclipse.jdt.core.compiler.problem.missingHashCodeMethod=warning
org.eclipse.jdt.core.compiler.problem.missingOverrideAnnotation=ignore
org.eclipse.jdt.core.compiler.problem.missingOverrideAnnotationForInterfaceMethodImplementation=enabled
org.eclipse.jdt.core.compiler.problem.missingSerialVersion=warning
org.eclipse.jdt.core.compiler.problem.missingSynchronizedOnInheritedMethod=warning
org.eclipse.jdt.core.compiler.problem.noEffectAssignment=warning
org.eclipse.jdt.core.compiler.problem.noImplicitStringConversion=warning
org.eclipse.jdt.core.compiler.problem.nonExternalizedStringLiteral=ignore
org.eclipse.jdt.core.compiler.problem.nonnullParameterAnnotationDropped=warning
org.eclipse.jdt.core.compiler.problem.nullAnnotationInferenceConflict=error
org.eclipse.jdt.core.compiler.problem.nullReference=error
org.eclipse.jdt.core.compiler.problem.nullSpecViolation=error
org.eclipse.jdt.core.compiler.problem.nullUncheckedConversion=warning
org.eclipse.jdt.core.compiler.problem.overridingPackageDefaultMethod=warning
org.eclipse.jdt.core.compiler.problem.parameterAssignment=warning
org.eclipse.jdt.core.compiler.problem.possibleAccidentalBooleanAssignment=warning
org.eclipse.jdt.core.compiler.problem.potentialNullReference=error
org.eclipse.jdt.core.compiler.problem.potentiallyUnclosedCloseable=ignore
org.eclipse.jdt.core.compiler.problem.rawTypeReference=warning
org.eclipse.jdt.core.compiler.problem.redundantNullAnnotation=warning
org.eclipse.jdt.core.compiler.problem.redundantNullCheck=warning
org.eclipse.jdt.core.compiler.problem.redundantSpecificationOfTypeArguments=ignore
org.eclipse.jdt.core.compiler.problem.redundantSuperinterface=ignore
org.eclipse.jdt.core.compiler.problem.reportMethodCanBePotentiallyStatic=ignore
org.eclipse.jdt.core.compiler.problem.reportMethodCanBeStatic=ignore
org.eclipse.jdt.core.compiler.problem.specialParameterHidingField=disabled
org.eclipse.jdt.core.compiler.problem.staticAccessReceiver=warning
org.eclipse.jdt.core.compiler.problem.suppressOptionalErrors=disabled
org.eclipse.jdt.core.compiler.problem.suppressWarnings=enabled
org.eclipse.jdt.core.compiler.problem.syntacticNullAnalysisForFields=disabled
org.eclipse.jdt.core.compiler.problem.syntheticAccessEmulation=ignore
org.eclipse.jdt.core.compiler.problem.typeParameterHiding=warning
org.eclipse.jdt.core.compiler.problem.unavoidableGenericTypeProblems=enabled
org.eclipse.jdt.core.compiler.problem.uncheckedTypeOperation=warning
org.eclipse.jdt.core.compiler.problem.unclosedCloseable=warning
org.eclipse.jdt.core.compiler.problem.undocumentedEmptyBlock=warning
org.eclipse.jdt.core.compiler.problem.unhandledWarningToken=warning
org.eclipse.jdt.core.compiler.problem.unnecessaryElse=ignore
org.eclipse.jdt.core.compiler.problem.unnecessaryTypeCheck=warning
org.eclipse.jdt.core.compiler.problem.unqualifiedFieldAccess=ignore
org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownException=warning
org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionExemptExceptionAndThrowable=enabled
org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionIncludeDocCommentReference=enabled
org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionWhenOverriding=disabled
org.eclipse.jdt.core.compiler.problem.unusedImport=warning
org.eclipse.jdt.core.compiler.problem.unusedLabel=warning
org.eclipse.jdt.core.compiler.problem.unusedLocal=warning
org.eclipse.jdt.core.compiler.problem.unusedObjectAllocation=warning
org.eclipse.jdt.core.compiler.problem.unusedParameter=warning
org.eclipse.jdt.core.compiler.problem.unusedParameterIncludeDocCommentReference=enabled
org.eclipse.jdt.core.compiler.problem.unusedParameterWhenImplementingAbstract=disabled
org.eclipse.jdt.core.compiler.problem.unusedParameterWhenOverridingConcrete=disabled
org.eclipse.jdt.core.compiler.problem.unusedPrivateMember=warning
org.eclipse.jdt.core.compiler.problem.unusedTypeParameter=warning
org.eclipse.jdt.core.compiler.problem.unusedWarningToken=warning
org.eclipse.jdt.core.compiler.problem.varargsArgumentNeedCast=warning
org.eclipse.jdt.core.compiler.source=1.6

View File

@ -29,6 +29,14 @@
<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>
-->
<!-- General -->
<dependency>
@ -36,6 +44,11 @@
<artifactId>commons-lang3</artifactId>
<version>3.2.1</version>
</dependency>
<dependency>
<groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId>
<version>1.9</version>
</dependency>
<!-- Logging -->
<dependency>
@ -63,7 +76,7 @@
<version>1.3.2</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>

View File

@ -1,19 +1,26 @@
package ca.uhn.fhir.context;
import static org.apache.commons.lang3.StringUtils.isBlank;
import static org.apache.commons.lang3.StringUtils.*;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Set;
import ca.uhn.fhir.model.api.IElement;
import ca.uhn.fhir.util.BeanUtils;
public abstract class BaseRuntimeChildDefinition {
private final Field myField;
private final int myMin;
private final int myMax;
private final IAccessor myAccessor;
private final String myElementName;
private final Field myField;
private final int myMax;
private final int myMin;
private final IMutator myMutator;
BaseRuntimeChildDefinition(Field theField, int theMin, int theMax, String theElementName) throws ConfigurationException {
super();
@ -29,34 +36,96 @@ public abstract class BaseRuntimeChildDefinition {
if (isBlank(theElementName)) {
throw new ConfigurationException("Element name must not be blank");
}
myField=theField;
myMin=theMin;
myMax=theMax;
myField = theField;
myMin = theMin;
myMax = theMax;
myElementName = theElementName;
// TODO: handle lists (max>0), and maybe max=0?
if (myMax == 1) {
Class<?> declaringClass = myField.getDeclaringClass();
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);
}
}
};
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;
}
}
public IAccessor getAccessor() {
return myAccessor;
}
public abstract BaseRuntimeElementDefinition<?> getChildByName(String theName);
public String getElementName() {
return myElementName;
}
public int getMin() {
return myMin;
public Field getField() {
return myField;
}
public int getMax() {
return myMax;
}
public Field getField() {
return myField;
public int getMin() {
return myMin;
}
public IMutator getMutator() {
return myMutator;
}
public abstract Set<String> getValidChildNames();
public abstract BaseRuntimeElementDefinition<?> getChildByName(String theName);
abstract void sealAndInitialize(Map<Class<? extends IElement>, BaseRuntimeElementDefinition<?>> theClassToElementDefinitions);
public interface IMutator {
void addValue(Object theTarget, Object theValue);
}
public interface IAccessor {
List<Object> getValues(Object theTarget);
}
}

View File

@ -23,8 +23,8 @@ public abstract class BaseRuntimeElementCompositeDefinition<T extends IComposite
myChildren.add(theNext);
}
public BaseRuntimeElementDefinition<?> getChildByNameOrThrowDataFormatException(String theName) throws DataFormatException {
BaseRuntimeElementDefinition<?> retVal = myNameToChild.get(theName);
public BaseRuntimeChildDefinition getChildByNameOrThrowDataFormatException(String theName) throws DataFormatException {
BaseRuntimeChildDefinition retVal = myNameToChild.get(theName);
if (retVal == null) {
throw new DataFormatException("Unknown child name: " + theName);
}
@ -37,7 +37,7 @@ public abstract class BaseRuntimeElementCompositeDefinition<T extends IComposite
next.sealAndInitialize(theClassToElementDefinitions);
}
myNameToChild = new HashMap<String, BaseRuntimeElementDefinition<?>>();
myNameToChild = new HashMap<String, BaseRuntimeChildDefinition>();
for (BaseRuntimeChildDefinition next : myChildren) {
for (String nextName : next.getValidChildNames()) {
if (myNameToChild.containsKey(nextName)) {

View File

@ -22,6 +22,16 @@ public abstract class BaseRuntimeElementDefinition<T extends IElement> {
return myName;
}
public T newInstance() {
try {
return getImplementingClass().newInstance();
} catch (InstantiationException e) {
throw new ConfigurationException("Failed to instantiate type:"+getImplementingClass().getName(), e);
} catch (IllegalAccessException e) {
throw new ConfigurationException("Failed to instantiate type:"+getImplementingClass().getName(), e);
}
}
public Class<? extends T> getImplementingClass() {
return myImplementingClass;
}

View File

@ -1,6 +1,6 @@
package ca.uhn.fhir.context;
import static org.apache.commons.lang3.StringUtils.isBlank;
import static org.apache.commons.lang3.StringUtils.*;
import java.lang.reflect.Field;
import java.util.ArrayList;
@ -8,9 +8,12 @@ import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
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;
import ca.uhn.fhir.model.api.ICodeEnum;
@ -24,10 +27,12 @@ import ca.uhn.fhir.model.api.ResourceReference;
import ca.uhn.fhir.model.api.annotation.Child;
import ca.uhn.fhir.model.api.annotation.ChildResource;
import ca.uhn.fhir.model.api.annotation.Choice;
import ca.uhn.fhir.model.api.annotation.DatatypeDef;
import ca.uhn.fhir.model.api.annotation.CodeTableDef;
import ca.uhn.fhir.model.api.annotation.DatatypeDef;
import ca.uhn.fhir.model.api.annotation.Narrative;
import ca.uhn.fhir.model.api.annotation.ResourceDef;
import ca.uhn.fhir.model.datatype.ICodedDatatype;
import ca.uhn.fhir.model.datatype.NarrativeDt;
class ModelScanner {
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(ModelScanner.class);
@ -35,6 +40,7 @@ class ModelScanner {
private Map<Class<? extends IElement>, BaseRuntimeElementDefinition<?>> myClassToElementDefinitions = new HashMap<Class<? extends IElement>, BaseRuntimeElementDefinition<?>>();
private Map<String, RuntimeResourceDefinition> myNameToResourceDefinitions = new HashMap<String, RuntimeResourceDefinition>();
private Set<Class<? extends IElement>> myScanAlso = new HashSet<Class<? extends IElement>>();
private Set<Class<? extends ICodeEnum>> myScanAlsoCodeTable = new HashSet<Class<? extends ICodeEnum>>();
// private Map<String, RuntimeResourceDefinition>
// myNameToDatatypeDefinitions = new HashMap<String,
@ -47,11 +53,13 @@ class ModelScanner {
ModelScanner(Class<? extends IResource>... theResourceTypes) throws ConfigurationException {
Set<Class<? extends IElement>> toScan = new HashSet<Class<? extends IElement>>(Arrays.asList(theResourceTypes));
toScan.add(NarrativeDt.class);
do {
for (Class<? extends IElement> nextClass : toScan) {
scan(nextClass);
}
for (Iterator<Class<? extends IElement>> iter = myScanAlso.iterator(); iter.hasNext(); ) {
for (Iterator<Class<? extends IElement>> iter = myScanAlso.iterator(); iter.hasNext();) {
if (myClassToElementDefinitions.containsKey(iter.next())) {
iter.remove();
}
@ -60,11 +68,13 @@ class ModelScanner {
toScan.addAll(myScanAlso);
myScanAlso.clear();
} while (!myScanAlso.isEmpty());
for (BaseRuntimeElementDefinition<?> next : myClassToElementDefinitions.values()) {
next.sealAndInitialize(myClassToElementDefinitions);
}
ourLog.info("Done scanning FHIR library, found {} model entries", myClassToElementDefinitions.size());
}
private String scan(Class<? extends IElement> theClass) throws ConfigurationException {
@ -76,8 +86,7 @@ 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;
@ -91,12 +100,11 @@ class ModelScanner {
Class<? extends ICompositeDatatype> resClass = (Class<? extends ICompositeDatatype>) theClass;
return scanCompositeDatatype(resClass, datatypeDefinition);
} else if (IPrimitiveDatatype.class.isAssignableFrom(theClass)) {
@SuppressWarnings("unchecked")
@SuppressWarnings({ "unchecked", "rawtypes" })
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());
}
}
@ -107,13 +115,11 @@ 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) {
@ -126,8 +132,7 @@ 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;
}
@ -150,8 +155,7 @@ 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;
}
@ -172,8 +176,7 @@ 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;
}
@ -187,10 +190,52 @@ class ModelScanner {
return resourceName;
}
@SuppressWarnings("unchecked")
private void scanCompositeElementForChildren(Class<? extends ICompositeElement> theClass, BaseRuntimeElementCompositeDefinition<?> theDefinition) {
Set<String> elementNames = new HashSet<String>();
Map<Integer, BaseRuntimeChildDefinition> orderToElementDef = new HashMap<Integer, BaseRuntimeChildDefinition>();
for (Field next : theClass.getFields()) {
TreeMap<Integer, BaseRuntimeChildDefinition> orderToElementDef = new TreeMap<Integer, BaseRuntimeChildDefinition>();
LinkedList<Class<? extends ICompositeElement>> classes = new LinkedList<Class<? extends ICompositeElement>>();
Class<? extends ICompositeElement> current = theClass;
do {
classes.push(current);
if (ICompositeElement.class.isAssignableFrom(current.getSuperclass())) {
current = (Class<? extends ICompositeElement>) current.getSuperclass();
}else {
current = null;
}
}while (current != null);
for (Class<? extends ICompositeElement> next : classes) {
scanCompositeElementForChildren(next, theDefinition, elementNames, orderToElementDef);
}
dealwithnegative
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)");
}
BaseRuntimeChildDefinition next = orderToElementDef.get(i);
theDefinition.addChild(next);
}
}
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);
if (hasNarrative != null) {
RuntimeChildNarrativeDefinition def;
try {
def = new RuntimeChildNarrativeDefinition(next, hasNarrative.name());
} catch (Exception e) {
throw new ConfigurationException("Failed to find narrative field", e);
}
theDefinition.addChild(def);
}
Child element = next.getAnnotation(Child.class);
if (element == null) {
ourLog.debug("Ignoring non-type field: " + next.getName());
@ -202,6 +247,10 @@ class ModelScanner {
int min = element.min();
int max = element.max();
while (order == Child.ORDER_UNKNOWN && orderToElementDef.containsKey(order)) {
order--;
}
Choice choiceAttr = element.choice();
List<Class<? extends IElement>> choiceTypes = new ArrayList<Class<? extends IElement>>();
for (Class<? extends IElement> nextChoiceType : choiceAttr.types()) {
@ -230,8 +279,7 @@ 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();
@ -242,12 +290,10 @@ 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");
}
if (!IDatatype.class.isAssignableFrom(next.getType())) {
throw new ConfigurationException("Field '" + elementName + "' in type '" + theClass.getCanonicalName() + "' is not a resource reference and is not an instance of type "
+ IDatatype.class.getName());
throw new ConfigurationException("Field '" + elementName + "' in type '" + theClass.getCanonicalName() + "' is not a resource reference and is not an instance of type " + IDatatype.class.getName());
}
@SuppressWarnings("unchecked")
@ -264,11 +310,10 @@ 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();
myScanAlso.add(type);
myScanAlsoCodeTable.add(type);
def.setCodeType(type);
}
}
@ -280,8 +325,11 @@ class ModelScanner {
// Class<? extends ICodeEnum> codeType = concept.type();
// String codeTableName = scanCodeTable(codeType);
// @SuppressWarnings("unchecked")
// String datatypeName = scan((Class<? extends IDatatype>) next.getType());
// RuntimeChildCompositeDatatypeDefinition def = new RuntimeChildCompositeDatatypeDefinition(next, elementName, datatypeName, min, max, codeTableName);
// String datatypeName = scan((Class<? extends IDatatype>)
// next.getType());
// RuntimeChildCompositeDatatypeDefinition def = new
// RuntimeChildCompositeDatatypeDefinition(next, elementName,
// datatypeName, min, max, codeTableName);
// orderToElementDef.put(order, def);
// } else {
// @SuppressWarnings("unchecked")
@ -291,16 +339,6 @@ class ModelScanner {
elementNames.add(elementName);
}
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)");
}
BaseRuntimeChildDefinition next = orderToElementDef.get(i);
theDefinition.addChild(next);
}
}
private String scanCodeTable(Class<? extends ICodeEnum> theCodeType, CodeTableDef theCodeTableDefinition) {

View File

@ -0,0 +1,13 @@
package ca.uhn.fhir.context;
import java.lang.reflect.Field;
import ca.uhn.fhir.model.datatype.NarrativeDt;
public class RuntimeChildNarrativeDefinition extends BaseRuntimeChildDatatypeDefinition {
public RuntimeChildNarrativeDefinition(Field theField, String theElementName) {
super(theField, theElementName, 1, 1, NarrativeDt.class);
}
}

View File

@ -8,16 +8,6 @@ public class RuntimeResourceDefinition extends BaseRuntimeElementCompositeDefini
super(theName, theClass);
}
public IResource newInstance() {
try {
return getImplementingClass().newInstance();
} catch (InstantiationException e) {
throw new ConfigurationException("Failed to instantiate type:"+getImplementingClass().getName(), e);
} catch (IllegalAccessException e) {
throw new ConfigurationException("Failed to instantiate type:"+getImplementingClass().getName(), e);
}
}
@Override
public ca.uhn.fhir.context.BaseRuntimeElementDefinition.ChildTypeEnum getChildType() {
return ChildTypeEnum.RESOURCE;

View File

@ -1,6 +1,8 @@
package ca.uhn.fhir.model.api;
public class BasePrimitiveDatatype extends BaseDatatype implements IPrimitiveDatatype {
public abstract class BasePrimitiveDatatype<T> extends BaseDatatype implements IPrimitiveDatatype<T> {
// nothing yet
}

View File

@ -1,5 +1,5 @@
package ca.uhn.fhir.model.api;
public interface ICodeEnum extends IPrimitiveDatatype {
public interface ICodeEnum {
// nothing yet
}

View File

@ -1,5 +1,14 @@
package ca.uhn.fhir.model.api;
public interface IPrimitiveDatatype extends IDatatype {
import ca.uhn.fhir.parser.DataFormatException;
public interface IPrimitiveDatatype<T> extends IDatatype {
void setValueAsString(String theValue) throws DataFormatException;
String getValueAsString();
T getValue();
void setValue(T theValue) throws DataFormatException;
}

View File

@ -0,0 +1,14 @@
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;
@Retention(RetentionPolicy.RUNTIME)
@Target(value= {ElementType.FIELD})
public @interface IsIdentifier {
// nothing
}

View File

@ -0,0 +1,14 @@
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;
@Retention(RetentionPolicy.RUNTIME)
@Target(value= {ElementType.FIELD})
public @interface Narrative {
String name();
}

View File

@ -1,11 +1,41 @@
package ca.uhn.fhir.model.datatype;
import org.apache.commons.codec.binary.Base64;
import ca.uhn.fhir.model.api.BasePrimitiveDatatype;
import ca.uhn.fhir.model.api.annotation.DatatypeDef;
@DatatypeDef(name="base64Binary")
public class Base64BinaryDt extends BasePrimitiveDatatype {
@DatatypeDef(name = "base64Binary")
public class Base64BinaryDt extends BasePrimitiveDatatype<byte[]> {
private byte[] myValue;
@Override
public void setValueAsString(String theValue) {
if (theValue == null) {
myValue = null;
} else {
myValue = Base64.decodeBase64(theValue);
}
}
@Override
public String getValueAsString() {
if (myValue == null) {
return null;
} else {
return Base64.encodeBase64String(myValue);
}
}
@Override
public void setValue(byte[] theValue) {
myValue = theValue;
}
@Override
public byte[] getValue() {
return myValue;
}
}

View File

@ -0,0 +1,162 @@
package ca.uhn.fhir.model.datatype;
import java.text.ParseException;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.TimeZone;
import org.apache.commons.lang3.time.FastDateFormat;
import ca.uhn.fhir.model.api.BasePrimitiveDatatype;
import ca.uhn.fhir.parser.DataFormatException;
public abstract class BaseDateTimeDt extends BasePrimitiveDatatype<Date> {
private static final FastDateFormat ourYearFormat = FastDateFormat.getInstance("yyyy");
private static final FastDateFormat ourYearMonthDayFormat = FastDateFormat.getInstance("yyyy-MM-dd");
private static final FastDateFormat ourYearMonthFormat = FastDateFormat.getInstance("yyyy-MM");
private static final FastDateFormat ourYearMonthDayTimeFormat = FastDateFormat.getInstance("yyyy-MM-dd'T'HH:mm:ss");
private static final FastDateFormat ourYearMonthDayTimeZoneFormat = FastDateFormat.getInstance("yyyy-MM-dd'T'HH:mm:ssX");
private int myPrecision = Calendar.SECOND;
private Date myValue;
private TimeZone myTimeZone;
private boolean myTimeZoneZulu = false;
/**
* Gets the precision for this datatype using field values from
* {@link Calendar}, such as {@link Calendar#MONTH}. Default is
* {@link Calendar#DAY_OF_MONTH}
*
* @see #setPrecision(int)
*/
public int getPrecision() {
return myPrecision;
}
@Override
public Date getValue() {
return myValue;
}
@Override
public String getValueAsString() {
if (myValue == null) {
return null;
} else {
switch (myPrecision) {
case Calendar.DAY_OF_MONTH:
return ourYearMonthDayFormat.format(myValue);
case Calendar.MONTH:
return ourYearMonthFormat.format(myValue);
case Calendar.YEAR:
return ourYearFormat.format(myValue);
case Calendar.SECOND:
if (myTimeZoneZulu) {
GregorianCalendar cal = new GregorianCalendar(TimeZone.getTimeZone("GMT"));
cal.setTime(myValue);
return ourYearMonthDayTimeZoneFormat.format(cal)+"Z";
} else if (myTimeZone != null) {
GregorianCalendar cal = new GregorianCalendar(myTimeZone);
cal.setTime(myValue);
return ourYearMonthDayTimeZoneFormat.format(cal);
} else {
return ourYearMonthDayTimeFormat.format(myValue);
}
}
throw new IllegalStateException("Invalid precition (this is a HAPI bug, shouldn't happen): " + myPrecision);
}
}
/**
* Sets the precision for this datatype using field values from
* {@link Calendar}. Valid values are:
* <ul>
* <li>{@link Calendar#SECOND}
* <li>{@link Calendar#DAY_OF_MONTH}
* <li>{@link Calendar#MONTH}
* <li>{@link Calendar#YEAR}
* </ul>
*
* @throws DataFormatException
*/
public void setPrecision(int thePrecision) throws DataFormatException {
switch (thePrecision) {
case Calendar.DAY_OF_MONTH:
case Calendar.MONTH:
case Calendar.YEAR:
case Calendar.SECOND:
myPrecision = thePrecision;
break;
default:
throw new DataFormatException("Invalid precision value");
}
}
@Override
public void setValue(Date theValue) throws DataFormatException {
myValue = theValue;
}
@Override
public void setValueAsString(String theValue) throws DataFormatException {
try {
if (theValue == null) {
myValue = null;
clearTimeZone();
} else if (theValue.length() == 4 && isPrecisionAllowed(Calendar.YEAR)) {
setValue(ourYearFormat.parse(theValue));
setPrecision(Calendar.YEAR);
clearTimeZone();
} else if (theValue.length() == 7 && isPrecisionAllowed(Calendar.MONTH)) {
setValue(ourYearMonthFormat.parse(theValue));
setPrecision(Calendar.MONTH);
clearTimeZone();
} else if (theValue.length() == 9 && isPrecisionAllowed(Calendar.DAY_OF_MONTH)) {
setValue(ourYearMonthDayFormat.parse(theValue));
setPrecision(Calendar.DAY_OF_MONTH);
clearTimeZone();
} else if ((theValue.length() == 18 || theValue.length() == 19 || theValue.length() == 24) && isPrecisionAllowed(Calendar.SECOND)) {
ourYearMonthDayTimeZoneFormat.parse(theValue);
setPrecision(Calendar.SECOND);
clearTimeZone();
if (theValue.length() == 19 && theValue.charAt(theValue.length()-1) == 'Z') {
myTimeZoneZulu = true;
}
} else {
throw new DataFormatException("Invalid date string");
}
} catch (ParseException e) {
throw new DataFormatException("Invalid date string");
}
}
public TimeZone getTimeZone() {
return myTimeZone;
}
public void setTimeZone(TimeZone theTimeZone) {
myTimeZone = theTimeZone;
}
public boolean isTimeZoneZulu() {
return myTimeZoneZulu;
}
public void setTimeZoneZulu(boolean theTimeZoneZulu) {
myTimeZoneZulu = theTimeZoneZulu;
}
private void clearTimeZone() {
myTimeZone=null;
myTimeZoneZulu=false;
}
/**
* To be implemented by subclasses to indicate whether the given precision is allowed by this type
*/
abstract boolean isPrecisionAllowed(int thePrecision);
}

View File

@ -2,10 +2,37 @@ package ca.uhn.fhir.model.datatype;
import ca.uhn.fhir.model.api.BasePrimitiveDatatype;
import ca.uhn.fhir.model.api.annotation.DatatypeDef;
import ca.uhn.fhir.parser.DataFormatException;
@DatatypeDef(name="boolean")
public class BooleanDt extends BasePrimitiveDatatype {
public class BooleanDt extends BasePrimitiveDatatype<Boolean> {
private boolean myValue;
private Boolean myValue;
@Override
public void setValueAsString(String theValue) throws DataFormatException {
if ("true".equals(theValue)) {
myValue = Boolean.TRUE;
}else if ("false".equals(theValue)) {
myValue=Boolean.FALSE;
}else {
throw new DataFormatException("Invalid boolean string: '" + theValue + "'");
}
}
@Override
public String getValueAsString() {
return null;
}
@Override
public void setValue(Boolean theValue) {
myValue = theValue;
}
@Override
public Boolean getValue() {
return myValue;
}
}

View File

@ -3,8 +3,39 @@ package ca.uhn.fhir.model.datatype;
import ca.uhn.fhir.model.api.BasePrimitiveDatatype;
import ca.uhn.fhir.model.api.ICodeEnum;
import ca.uhn.fhir.model.api.annotation.DatatypeDef;
import ca.uhn.fhir.parser.DataFormatException;
@DatatypeDef(name="code")
public class CodeDt<T extends ICodeEnum> extends BasePrimitiveDatatype implements ICodedDatatype {
@DatatypeDef(name = "code")
public class CodeDt<T extends ICodeEnum> extends BasePrimitiveDatatype<String> implements ICodedDatatype {
private String myValue;
public String getValue() {
return myValue;
}
public void setValue(String theValue) throws DataFormatException {
if (theValue == null) {
myValue = null;
} else {
if (theValue.length() == 0) {
throw new DataFormatException("Value can not be empty");
}
if (Character.isWhitespace(theValue.charAt(0)) || Character.isWhitespace(theValue.charAt(theValue.length()-1))){
throw new DataFormatException("Value must not contain trailing or leading whitespace");
}
myValue = theValue;
}
}
@Override
public void setValueAsString(String theValue) throws DataFormatException {
setValue(theValue);
}
@Override
public String getValueAsString() {
return getValue();
}
}

View File

@ -1,15 +1,23 @@
package ca.uhn.fhir.model.datatype;
import java.util.GregorianCalendar;
import java.util.Calendar;
import ca.uhn.fhir.model.api.BaseDatatype;
import ca.uhn.fhir.model.api.IPrimitiveDatatype;
import ca.uhn.fhir.model.api.annotation.DatatypeDef;
@DatatypeDef(name="date")
public class DateDt extends BaseDatatype implements IPrimitiveDatatype {
@DatatypeDef(name = "date")
public class DateDt extends BaseDateTimeDt {
@Override
boolean isPrecisionAllowed(int thePrecision) {
switch (thePrecision) {
case Calendar.YEAR:
case Calendar.MONTH:
case Calendar.DATE:
return true;
default:
return false;
}
}
private GregorianCalendar myValue;
private int myPrecision;
}

View File

@ -1,15 +1,23 @@
package ca.uhn.fhir.model.datatype;
import java.util.GregorianCalendar;
import java.util.Calendar;
import ca.uhn.fhir.model.api.BasePrimitiveDatatype;
import ca.uhn.fhir.model.api.annotation.DatatypeDef;
@DatatypeDef(name="dateTime")
public class DateTimeDt extends BasePrimitiveDatatype {
@DatatypeDef(name = "dateTime")
public class DateTimeDt extends BaseDateTimeDt {
@Override
boolean isPrecisionAllowed(int thePrecision) {
switch (thePrecision) {
case Calendar.YEAR:
case Calendar.MONTH:
case Calendar.DATE:
case Calendar.SECOND:
return true;
default:
return false;
}
}
private GregorianCalendar myValue;
private int myPrecision;
}

View File

@ -4,10 +4,46 @@ import java.math.BigDecimal;
import ca.uhn.fhir.model.api.BasePrimitiveDatatype;
import ca.uhn.fhir.model.api.annotation.DatatypeDef;
import ca.uhn.fhir.parser.DataFormatException;
@DatatypeDef(name="decimal")
public class DecimalDt extends BasePrimitiveDatatype {
@DatatypeDef(name = "decimal")
public class DecimalDt extends BasePrimitiveDatatype<BigDecimal> {
private BigDecimal myValue;
@Override
public void setValueAsString(String theValue) throws DataFormatException {
if (theValue == null) {
myValue = null;
} else {
myValue = new BigDecimal(theValue);
}
}
@Override
public String getValueAsString() {
if (myValue == null) {
return null;
}
return myValue.toPlainString();
}
@Override
public BigDecimal getValue() {
return myValue;
}
@Override
public void setValue(BigDecimal theValue) throws DataFormatException {
myValue = theValue;
}
public void setValueAsInteger(int theValue) {
myValue = new BigDecimal(theValue);
}
public int getValueAsInteger() {
return myValue.intValue();
}
}

View File

@ -1,13 +1,15 @@
package ca.uhn.fhir.model.datatype;
import java.util.Date;
import java.util.Calendar;
import ca.uhn.fhir.model.api.BasePrimitiveDatatype;
import ca.uhn.fhir.model.api.annotation.DatatypeDef;
@DatatypeDef(name="instant")
public class InstantDt extends BasePrimitiveDatatype {
public class InstantDt extends BaseDateTimeDt {
private Date myValue;
@Override
boolean isPrecisionAllowed(int thePrecision) {
return thePrecision == Calendar.SECOND;
}
}

View File

@ -2,10 +2,36 @@ package ca.uhn.fhir.model.datatype;
import ca.uhn.fhir.model.api.BasePrimitiveDatatype;
import ca.uhn.fhir.model.api.annotation.DatatypeDef;
import ca.uhn.fhir.parser.DataFormatException;
@DatatypeDef(name="integer")
public class IntegerDt extends BasePrimitiveDatatype {
public class IntegerDt extends BasePrimitiveDatatype<Integer> {
private int myValue;
private Integer myValue;
public Integer getValue() {
return myValue;
}
public void setValue(Integer theValue) {
myValue = theValue;
}
@Override
public void setValueAsString(String theValue) throws DataFormatException {
if (theValue == null) {
myValue = null;
}else {
myValue = Integer.parseInt(theValue);
}
}
@Override
public String getValueAsString() {
if (myValue==null) {
return null;
}
return Integer.toString(myValue);
}
}

View File

@ -0,0 +1,37 @@
package ca.uhn.fhir.model.datatype;
import ca.uhn.fhir.model.api.BaseCompositeDatatype;
import ca.uhn.fhir.model.api.CodeableConceptElement;
import ca.uhn.fhir.model.api.annotation.Child;
import ca.uhn.fhir.model.api.annotation.DatatypeDef;
import ca.uhn.fhir.model.enm.NarrativeStatusEnum;
@DatatypeDef(name="Narrative")
public class NarrativeDt extends BaseCompositeDatatype {
@Child(name="status", order=0, min=1)
@CodeableConceptElement(type=NarrativeStatusEnum.class)
private CodeDt<NarrativeStatusEnum> myStatus;
@Child(name="div", order=1)
private StringDt myDiv;
public StringDt getDiv() {
return myDiv;
}
public CodeDt<NarrativeStatusEnum> getStatus() {
return myStatus;
}
public void setDiv(StringDt theDiv) {
myDiv = theDiv;
}
public void setStatus(CodeDt<NarrativeStatusEnum> theStatus) {
myStatus = theStatus;
}
}

View File

@ -2,10 +2,31 @@ package ca.uhn.fhir.model.datatype;
import ca.uhn.fhir.model.api.BasePrimitiveDatatype;
import ca.uhn.fhir.model.api.annotation.DatatypeDef;
import ca.uhn.fhir.parser.DataFormatException;
@DatatypeDef(name="string")
public class StringDt extends BasePrimitiveDatatype {
@DatatypeDef(name = "string")
public class StringDt extends BasePrimitiveDatatype<String> {
private String myValue;
@Override
public String getValue() {
return myValue;
}
@Override
public String getValueAsString() {
return myValue;
}
@Override
public void setValue(String theValue) throws DataFormatException {
myValue = theValue;
}
@Override
public void setValueAsString(String theValue) throws DataFormatException {
myValue = theValue;
}
}

View File

@ -1,12 +1,46 @@
package ca.uhn.fhir.model.datatype;
import java.net.URI;
import java.net.URISyntaxException;
import ca.uhn.fhir.model.api.BaseDatatype;
import ca.uhn.fhir.model.api.IPrimitiveDatatype;
import ca.uhn.fhir.model.api.annotation.DatatypeDef;
import ca.uhn.fhir.parser.DataFormatException;
@DatatypeDef(name="uri")
public class UriDt extends BaseDatatype implements IPrimitiveDatatype {
@DatatypeDef(name = "uri")
public class UriDt extends BaseDatatype implements IPrimitiveDatatype<URI> {
private URI myValue;
public URI getValue() {
return myValue;
}
public void setValue(URI theValue) {
myValue = theValue;
}
@Override
public void setValueAsString(String theValue) throws DataFormatException {
if (theValue==null) {
myValue=null;
}else {
try {
myValue = new URI(theValue);
} catch (URISyntaxException e) {
throw new DataFormatException("Unable to parse URI value", e);
}
}
}
@Override
public String getValueAsString() {
if (myValue == null) {
return null;
} else {
return myValue.toString();
}
}
private String myValue;
}

View File

@ -0,0 +1,26 @@
package ca.uhn.fhir.model.enm;
import ca.uhn.fhir.model.api.ICodeEnum;
import ca.uhn.fhir.model.api.annotation.Description;
import ca.uhn.fhir.model.api.annotation.EnumeratedCodeValue;
import ca.uhn.fhir.model.api.annotation.CodeTableDef;
@CodeTableDef(tableId = 28, name = "narrative-status")
public enum NarrativeStatusEnum implements ICodeEnum {
@EnumeratedCodeValue(value = "generated")
@Description("The contents of the narrative are entirely generated from the structured data in the resource.")
GENERATED,
@EnumeratedCodeValue(value = "extensions")
@Description("The contents of the narrative are entirely generated from the structured data in the resource and some of the content is generated from extensions.")
EXTENSIONS,
@EnumeratedCodeValue(value = "additional")
@Description("The contents of the narrative contain additional information not found in the structured data.")
ADDITIONAL,
@EnumeratedCodeValue(value = "empty")
@Description("the contents of the narrative are some equivalent of \"No human-readable text provided for this resource\".")
EMPTY
}

View File

@ -2,9 +2,22 @@ package ca.uhn.fhir.model.resource;
import ca.uhn.fhir.model.api.BaseElement;
import ca.uhn.fhir.model.api.IResource;
import ca.uhn.fhir.model.api.annotation.Narrative;
import ca.uhn.fhir.model.datatype.NarrativeDt;
public abstract class BaseResource extends BaseElement implements IResource {
@Narrative(name="text")
private NarrativeDt myText;
public NarrativeDt getText() {
return myText;
}
public void setText(NarrativeDt theText) {
myText = theText;
}
// public abstract void setAllChildValues(List<IElement> theChildren);
//
// public abstract List<IElement> getAllChildValues();

View File

@ -1,6 +1,7 @@
package ca.uhn.fhir.model.resource;
import ca.uhn.fhir.model.api.annotation.Child;
import ca.uhn.fhir.model.api.annotation.IsIdentifier;
import ca.uhn.fhir.model.datatype.IdentifierDt;
/**
@ -9,6 +10,15 @@ import ca.uhn.fhir.model.datatype.IdentifierDt;
public abstract class BaseResourceWithIdentifier extends BaseResource {
@Child(name="identifier", order=Child.ORDER_UNKNOWN)
@IsIdentifier
private IdentifierDt myIdentifier;
public IdentifierDt getIdentifier() {
return myIdentifier;
}
public void setIdentifier(IdentifierDt theIdentifier) {
myIdentifier = theIdentifier;
}
}

View File

@ -6,11 +6,13 @@ import ca.uhn.fhir.model.api.ResourceReference;
import ca.uhn.fhir.model.api.annotation.Child;
import ca.uhn.fhir.model.api.annotation.ChildResource;
import ca.uhn.fhir.model.api.annotation.Choice;
import ca.uhn.fhir.model.api.annotation.Narrative;
import ca.uhn.fhir.model.api.annotation.ResourceDef;
import ca.uhn.fhir.model.datatype.AttachmentDt;
import ca.uhn.fhir.model.datatype.CodeableConceptDt;
import ca.uhn.fhir.model.datatype.DateTimeDt;
import ca.uhn.fhir.model.datatype.InstantDt;
import ca.uhn.fhir.model.datatype.NarrativeDt;
import ca.uhn.fhir.model.datatype.PeriodDt;
import ca.uhn.fhir.model.datatype.QuantityDt;
import ca.uhn.fhir.model.datatype.RatioDt;
@ -77,6 +79,96 @@ public class Observation extends BaseResourceWithIdentifier {
Patient.class, Group.class // TODO: add device, location
})
private ResourceReference mySubject;
public CodeableConceptDt<ObservationCodesEnum> getName() {
return myName;
}
public void setName(CodeableConceptDt<ObservationCodesEnum> theName) {
myName = theName;
}
public IDatatype getValue() {
return myValue;
}
public void setValue(IDatatype theValue) {
myValue = theValue;
}
public CodeableConceptDt<ObservationInterpretationEnum> getInterpretation() {
return myInterpretation;
}
public void setInterpretation(CodeableConceptDt<ObservationInterpretationEnum> theInterpretation) {
myInterpretation = theInterpretation;
}
public StringDt getComments() {
return myComments;
}
public void setComments(StringDt theComments) {
myComments = theComments;
}
public IDatatype getApplies() {
return myApplies;
}
public void setApplies(IDatatype theApplies) {
myApplies = theApplies;
}
public InstantDt getIssued() {
return myIssued;
}
public void setIssued(InstantDt theIssued) {
myIssued = theIssued;
}
public CodeableConceptDt<ObservationStatusEnum> getStatus() {
return myStatus;
}
public void setStatus(CodeableConceptDt<ObservationStatusEnum> theStatus) {
myStatus = theStatus;
}
public CodeableConceptDt<ObservationStatusEnum> getReliability() {
return myReliability;
}
public void setReliability(CodeableConceptDt<ObservationStatusEnum> theReliability) {
myReliability = theReliability;
}
public CodeableConceptDt<BodySiteEnum> getBodySite() {
return myBodySite;
}
public void setBodySite(CodeableConceptDt<BodySiteEnum> theBodySite) {
myBodySite = theBodySite;
}
public CodeableConceptDt<ObservationMethodEnum> getMethod() {
return myMethod;
}
public void setMethod(CodeableConceptDt<ObservationMethodEnum> theMethod) {
myMethod = theMethod;
}
public ResourceReference getSubject() {
return mySubject;
}
public void setSubject(ResourceReference theSubject) {
mySubject = theSubject;
}
}

View File

@ -1,18 +1,44 @@
package ca.uhn.fhir.parser;
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.RuntimePrimitiveDatatypeDefinition;
import ca.uhn.fhir.context.RuntimeResourceDefinition;
import ca.uhn.fhir.model.api.BaseCompositeDatatype;
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;
class ParserState {
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(ParserState.class);
private FhirContext myContext;
private BaseState myState;
private Object myObject;
public ParserState(FhirContext theContext) {
myContext=theContext;
myContext = theContext;
}
public void attributeValue(String theValue) throws DataFormatException {
myState.attributeValue(theValue);
}
public void enteringNewElement(String theLocalPart) throws DataFormatException {
myState.enteringNewElement(theLocalPart);
}
private void push(BaseState theState) {
theState.setStack(myState);
myState = theState;
}
private void setState(BaseState theState) {
myState = theState;
}
public static ParserState getResourceInstance(FhirContext theContext, String theLocalPart) throws DataFormatException {
@ -20,58 +46,126 @@ class ParserState {
if (!(definition instanceof RuntimeResourceDefinition)) {
throw new DataFormatException("Element '" + theLocalPart + "' is not a resource, expected a resource at this position");
}
RuntimeResourceDefinition def = (RuntimeResourceDefinition) definition;
IResource instance = def.newInstance();
ParserState retVal = new ParserState(theContext);
retVal.setState(retVal.new ResourceParserState(def, instance));
retVal.setState(retVal.new ContainerState(def, instance));
return retVal;
}
private abstract class BaseState {
private BaseState myStack;
private void setState(BaseState theState) {
myState = theState;
public abstract void attributeValue(String theValue) throws DataFormatException;
public abstract void enteringNewElement(String theLocalPart) throws DataFormatException;
public void setStack(BaseState theState) {
myStack = theState;
}
private abstract class BaseState
{
private BaseState myStack;
public abstract void enteringNewElement(String theLocalPart) throws DataFormatException;
}
private class ResourceParserState extends BaseState
{
public abstract void endingElement(String theLocalPart);
private RuntimeResourceDefinition myResourceDefinition;
private IResource myInstance;
}
private class ContainerState extends BaseState {
public ResourceParserState(RuntimeResourceDefinition theDef, IResource theInstance) {
myResourceDefinition = theDef;
private BaseRuntimeElementCompositeDefinition<?> myDefinition;
private ICompositeElement myInstance;
public ContainerState(BaseRuntimeElementCompositeDefinition<?> theDef, ICompositeElement theInstance) {
myDefinition = theDef;
myInstance = theInstance;
}
@Override
public void enteringNewElement(String theChildName) throws DataFormatException {
BaseRuntimeElementDefinition<?> child = myResourceDefinition.getChildByNameOrThrowDataFormatException(theChildName);
switch (child.getChildType()) {
case COMPOSITE_DATATYPE:
break;
case PRIMITIVE_DATATYPE:
break;
case RESOURCE:
default:
throw new DataFormatException("Illegal resource position");
}
public void attributeValue(String theValue) {
ourLog.debug("Ignoring attribute value: {}", theValue);
}
@Override
public void enteringNewElement(String theChildName) throws DataFormatException {
BaseRuntimeChildDefinition child = myDefinition.getChildByNameOrThrowDataFormatException(theChildName);
BaseRuntimeElementDefinition<?> target = child.getChildByName(theChildName);
switch (target.getChildType()) {
case COMPOSITE_DATATYPE: {
BaseRuntimeElementCompositeDefinition<?> compositeTarget = (BaseRuntimeElementCompositeDefinition<?>) target;
ICompositeDatatype newChildInstance = (ICompositeDatatype) compositeTarget.newInstance();
child.getMutator().addValue(myInstance, newChildInstance);
ContainerState newState = new ContainerState(compositeTarget, newChildInstance);
push(newState);
break;
}
case PRIMITIVE_DATATYPE: {
RuntimePrimitiveDatatypeDefinition primitiveTarget = (RuntimePrimitiveDatatypeDefinition) target;
IPrimitiveDatatype<?> newChildInstance = primitiveTarget.newInstance();
child.getMutator().addValue(myInstance, newChildInstance);
PrimitiveState newState = new PrimitiveState(primitiveTarget, newChildInstance);
push(newState);
break;
}
case RESOURCE: {
break;
}
default:
throw new DataFormatException("Illegal resource position");
}
}
@Override
public void endingElement(String theLocalPart) {
pop();
if (myState == null) {
myObject = myInstance;
}
}
}
public void enteringNewElement(String theLocalPart) throws DataFormatException {
myState.enteringNewElement(theLocalPart);
private class PrimitiveState extends BaseState {
private RuntimePrimitiveDatatypeDefinition myDefinition;
private IPrimitiveDatatype<?> myInstance;
public PrimitiveState(RuntimePrimitiveDatatypeDefinition theDefinition, IPrimitiveDatatype<?> theInstance) {
super();
myDefinition = theDefinition;
myInstance = theInstance;
}
@Override
public void attributeValue(String theValue) throws DataFormatException {
myInstance.setValueAsString(theValue);
}
@Override
public void enteringNewElement(String theLocalPart) throws DataFormatException {
throw new Error("?? can this happen?"); // TODO: can this happen?
}
@Override
public void endingElement(String theLocalPart) {
pop();
}
}
public Object getObject() {
return myObject;
}
private void pop() {
myState = myState.myStack;
}
public boolean isComplete() {
return myObject != null;
}
public void endingElement(String theLocalPart) {
myState.endingElement(theLocalPart);
}
}

View File

@ -7,6 +7,8 @@ import javax.xml.stream.XMLEventFactory;
import javax.xml.stream.XMLEventReader;
import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.events.Attribute;
import javax.xml.stream.events.EndElement;
import javax.xml.stream.events.StartElement;
import javax.xml.stream.events.XMLEvent;
@ -52,6 +54,30 @@ public class XmlParser {
} else {
parserState.enteringNewElement(elem.getName().getLocalPart());
}
} else if (nextEvent.isAttribute()) {
Attribute elem = (Attribute) nextEvent;
if (!FHIR_NS.equals(elem.getName().getNamespaceURI())) {
continue;
}
if (!"value".equals(elem.getName().getLocalPart())) {
continue;
}
if (parserState == null) {
throw new DataFormatException("Detected attribute before element");
}
parserState.attributeValue(elem.getValue());
} else if (nextEvent.isEndElement()) {
EndElement elem = nextEvent.asEndElement();
if (!FHIR_NS.equals(elem.getName().getNamespaceURI())) {
continue;
}
if (parserState == null) {
throw new DataFormatException("Detected unexpected end-element");
}
parserState.endingElement(elem.getName().getLocalPart());
if (parserState.isComplete()) {
return (IResource) parserState.getObject();
}
}

View File

@ -0,0 +1,48 @@
package ca.uhn.fhir.util;
import java.beans.BeanInfo;
import java.beans.IntrospectionException;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Method;
public class BeanUtils {
public static Method findAccessor(Class<?> theClassToIntrospect, Class<?> theTargetReturnType, String thePropertyName) throws NoSuchFieldException {
BeanInfo info;
try {
info = Introspector.getBeanInfo(theClassToIntrospect);
} catch (IntrospectionException e) {
throw new NoSuchFieldException(e.getMessage());
}
for (PropertyDescriptor pd : info.getPropertyDescriptors()) {
if (thePropertyName.equals(pd.getName())) {
if (theTargetReturnType.isAssignableFrom(pd.getPropertyType())) {
return pd.getReadMethod();
}else {
throw new NoSuchFieldException(theClassToIntrospect + " has an accessor for field " + thePropertyName + " but it does not return type " + theTargetReturnType);
}
}
}
throw new NoSuchFieldException(theClassToIntrospect + " has no accessor for field " + thePropertyName);
}
public static Method findMutator(Class<?> theClassToIntrospect, Class<?> theTargetReturnType, String thePropertyName) throws NoSuchFieldException {
BeanInfo info;
try {
info = Introspector.getBeanInfo(theClassToIntrospect);
} catch (IntrospectionException e) {
throw new NoSuchFieldException(e.getMessage());
}
for (PropertyDescriptor pd : info.getPropertyDescriptors()) {
if (thePropertyName.equals(pd.getName())) {
if (theTargetReturnType.isAssignableFrom(pd.getPropertyType())) {
return pd.getWriteMethod();
}else {
throw new NoSuchFieldException(theClassToIntrospect + " has an mutator for field " + thePropertyName + " but it does not return type " + theTargetReturnType);
}
}
}
throw new NoSuchFieldException(theClassToIntrospect + " has no mutator for field " + thePropertyName);
}
}

View File

@ -0,0 +1,13 @@
package ca.uhn.fhir.model.datatype;
import org.junit.Test;
public class Base64BinaryDtTest {
@Test
public void testDecodeNull() {
new Base64BinaryDt().setValueAsString(null);
}
}