Almost have unit tests passing

This commit is contained in:
jamesagnew 2014-12-14 22:29:15 -05:00
parent ebd0f222f4
commit 59ba1c9f7b
11 changed files with 408 additions and 105 deletions

View File

@ -288,7 +288,7 @@ class ModelScanner {
scanCompositeDatatype(resClass, datatypeDefinition); scanCompositeDatatype(resClass, datatypeDefinition);
} else if (IPrimitiveType.class.isAssignableFrom(theClass)) { } else if (IPrimitiveType.class.isAssignableFrom(theClass)) {
@SuppressWarnings({ "unchecked" }) @SuppressWarnings({ "unchecked" })
Class<? extends IPrimitiveType> resClass = (Class<? extends IPrimitiveType>) theClass; Class<? extends IPrimitiveType<?>> resClass = (Class<? extends IPrimitiveType<?>>) theClass;
scanPrimitiveDatatype(resClass, datatypeDefinition); scanPrimitiveDatatype(resClass, datatypeDefinition);
} else { } 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());

View File

@ -300,10 +300,10 @@ public class Bundle extends BaseBundle /* implements IElement */{
} }
public InstantDt getPublished() { public InstantDt getPublished() {
InstantDt retVal = (InstantDt) getResourceMetadata().get(ResourceMetadataKeyEnum.UPDATED); InstantDt retVal = (InstantDt) getResourceMetadata().get(ResourceMetadataKeyEnum.PUBLISHED);
if (retVal == null) { if (retVal == null) {
retVal= new InstantDt(); retVal= new InstantDt();
getResourceMetadata().put(ResourceMetadataKeyEnum.UPDATED, retVal); getResourceMetadata().put(ResourceMetadataKeyEnum.PUBLISHED, retVal);
} }
return retVal; return retVal;
} }

View File

@ -85,11 +85,12 @@ import ca.uhn.fhir.model.dstu.resource.Binary;
import ca.uhn.fhir.model.primitive.BooleanDt; import ca.uhn.fhir.model.primitive.BooleanDt;
import ca.uhn.fhir.model.primitive.DecimalDt; import ca.uhn.fhir.model.primitive.DecimalDt;
import ca.uhn.fhir.model.primitive.IdDt; import ca.uhn.fhir.model.primitive.IdDt;
import ca.uhn.fhir.model.primitive.InstantDt;
import ca.uhn.fhir.model.primitive.IntegerDt; import ca.uhn.fhir.model.primitive.IntegerDt;
import ca.uhn.fhir.model.primitive.StringDt; import ca.uhn.fhir.model.primitive.StringDt;
import ca.uhn.fhir.model.primitive.XhtmlDt; import ca.uhn.fhir.model.primitive.XhtmlDt;
import ca.uhn.fhir.narrative.INarrativeGenerator; import ca.uhn.fhir.narrative.INarrativeGenerator;
import ca.uhn.fhir.util.ElementUtil;
import ca.uhn.fhir.util.UrlUtil;
public class JsonParser extends BaseParser implements IParser { public class JsonParser extends BaseParser implements IParser {
@ -116,7 +117,8 @@ public class JsonParser extends BaseParser implements IParser {
private boolean myPrettyPrint; private boolean myPrettyPrint;
/** /**
* Do not use this constructor, the recommended way to obtain a new instance of the JSON parser is to invoke {@link FhirContext#newJsonParser()}. * Do not use this constructor, the recommended way to obtain a new instance of the JSON parser is to invoke
* {@link FhirContext#newJsonParser()}.
*/ */
public JsonParser(FhirContext theContext) { public JsonParser(FhirContext theContext) {
super(theContext); super(theContext);
@ -246,10 +248,12 @@ public class JsonParser extends BaseParser implements IParser {
writeTagWithTextNode(theEventWriter, "id", theBundle.getId().getIdPart()); writeTagWithTextNode(theEventWriter, "id", theBundle.getId().getIdPart());
theEventWriter.writeStartObject("meta"); if (!ElementUtil.isEmpty(theBundle.getId().getVersionIdPart(), theBundle.getUpdated())) {
writeOptionalTagWithTextNode(theEventWriter, "versionId", theBundle.getId().getVersionIdPart()); theEventWriter.writeStartObject("meta");
writeOptionalTagWithTextNode(theEventWriter, "lastUpdated", theBundle.getUpdated()); writeOptionalTagWithTextNode(theEventWriter, "versionId", theBundle.getId().getVersionIdPart());
theEventWriter.writeEnd(); writeOptionalTagWithTextNode(theEventWriter, "lastUpdated", theBundle.getUpdated());
theEventWriter.writeEnd();
}
writeOptionalTagWithTextNode(theEventWriter, "type", theBundle.getType()); writeOptionalTagWithTextNode(theEventWriter, "type", theBundle.getType());
writeOptionalTagWithTextNode(theEventWriter, "base", theBundle.getLinkBase()); writeOptionalTagWithTextNode(theEventWriter, "base", theBundle.getLinkBase());
@ -311,8 +315,7 @@ public class JsonParser extends BaseParser implements IParser {
theEventWriter.writeEnd(); theEventWriter.writeEnd();
} }
private void encodeChildElementToStreamWriter(RuntimeResourceDefinition theResDef, IBaseResource theResource, JsonGenerator theWriter, IBase theNextValue, private void encodeChildElementToStreamWriter(RuntimeResourceDefinition theResDef, IBaseResource theResource, JsonGenerator theWriter, IBase theNextValue, BaseRuntimeElementDefinition<?> theChildDef, String theChildName, boolean theIsSubElementWithinResource) throws IOException {
BaseRuntimeElementDefinition<?> theChildDef, String theChildName, boolean theIsSubElementWithinResource) throws IOException {
switch (theChildDef.getChildType()) { switch (theChildDef.getChildType()) {
case PRIMITIVE_DATATYPE: { case PRIMITIVE_DATATYPE: {
@ -423,8 +426,7 @@ public class JsonParser extends BaseParser implements IParser {
} }
private void encodeCompositeElementChildrenToStreamWriter(RuntimeResourceDefinition theResDef, IBaseResource theResource, IBase theNextValue, JsonGenerator theEventWriter, private void encodeCompositeElementChildrenToStreamWriter(RuntimeResourceDefinition theResDef, IBaseResource theResource, IBase theNextValue, JsonGenerator theEventWriter, List<? extends BaseRuntimeChildDefinition> theChildren, boolean theIsSubElementWithinResource) throws IOException {
List<? extends BaseRuntimeChildDefinition> theChildren, boolean theIsSubElementWithinResource) throws IOException {
for (BaseRuntimeChildDefinition nextChild : theChildren) { for (BaseRuntimeChildDefinition nextChild : theChildren) {
if (nextChild instanceof RuntimeChildNarrativeDefinition) { if (nextChild instanceof RuntimeChildNarrativeDefinition) {
@ -527,20 +529,25 @@ public class JsonParser extends BaseParser implements IParser {
for (int i = 0; i < valueIdx; i++) { for (int i = 0; i < valueIdx; i++) {
boolean haveContent = false; boolean haveContent = false;
List<HeldExtension> heldExts = Collections.emptyList();
List<HeldExtension> heldModExts = Collections.emptyList();
if (extensions.size() > i && extensions.get(i) != null && extensions.get(i).isEmpty() == false) { if (extensions.size() > i && extensions.get(i) != null && extensions.get(i).isEmpty() == false) {
haveContent = true; haveContent = true;
theEventWriter.writeStartObject(); heldExts = extensions.get(i);
theEventWriter.writeStartArray("extension");
for (HeldExtension nextExt : extensions.get(i)) {
nextExt.write(theResDef, theResource, theEventWriter);
}
theEventWriter.writeEnd();
theEventWriter.writeEnd();
} }
if (modifierExtensions.size() > i && modifierExtensions.get(i) != null && modifierExtensions.get(i).isEmpty() == false) {
haveContent = true;
heldModExts = modifierExtensions.get(i);
}
if (!haveContent) { if (!haveContent) {
// theEventWriter.writeEnd();
theEventWriter.writeNull(); theEventWriter.writeNull();
} else {
theEventWriter.writeStartObject();
writeExtensionsAsDirectChild(theResource, theEventWriter, theResDef, heldExts, heldModExts, null);
theEventWriter.writeEnd();
} }
} }
@ -549,15 +556,13 @@ public class JsonParser extends BaseParser implements IParser {
} }
} }
private void encodeCompositeElementToStreamWriter(RuntimeResourceDefinition theResDef, IBaseResource theResource, IBase theNextValue, JsonGenerator theEventWriter, private void encodeCompositeElementToStreamWriter(RuntimeResourceDefinition theResDef, IBaseResource theResource, IBase theNextValue, JsonGenerator theEventWriter, BaseRuntimeElementCompositeDefinition<?> resDef, boolean theIsSubElementWithinResource) throws IOException, DataFormatException {
BaseRuntimeElementCompositeDefinition<?> resDef, boolean theIsSubElementWithinResource) throws IOException, DataFormatException { extractAndWriteExtensionsAsDirectChild(theNextValue, theEventWriter, resDef, theResDef, theResource, null);
extractAndWriteExtensionsAsDirectChild(theNextValue, theEventWriter, resDef, theResDef, theResource);
encodeCompositeElementChildrenToStreamWriter(theResDef, theResource, theNextValue, theEventWriter, resDef.getExtensions(), theIsSubElementWithinResource); encodeCompositeElementChildrenToStreamWriter(theResDef, theResource, theNextValue, theEventWriter, resDef.getExtensions(), theIsSubElementWithinResource);
encodeCompositeElementChildrenToStreamWriter(theResDef, theResource, theNextValue, theEventWriter, resDef.getChildren(), theIsSubElementWithinResource); encodeCompositeElementChildrenToStreamWriter(theResDef, theResource, theNextValue, theEventWriter, resDef.getChildren(), theIsSubElementWithinResource);
} }
private void encodeResourceToJsonStreamWriter(RuntimeResourceDefinition theResDef, IBaseResource theResource, JsonGenerator theEventWriter, String theObjectNameOrNull, private void encodeResourceToJsonStreamWriter(RuntimeResourceDefinition theResDef, IBaseResource theResource, JsonGenerator theEventWriter, String theObjectNameOrNull, boolean theIsSubElementWithinResource) throws IOException {
boolean theIsSubElementWithinResource) throws IOException {
String resourceId = null; String resourceId = null;
if (theResource instanceof IResource) { if (theResource instanceof IResource) {
IResource res = (IResource) theResource; IResource res = (IResource) theResource;
@ -578,8 +583,7 @@ public class JsonParser extends BaseParser implements IParser {
encodeResourceToJsonStreamWriter(theResDef, theResource, theEventWriter, theObjectNameOrNull, theIsSubElementWithinResource, resourceId); encodeResourceToJsonStreamWriter(theResDef, theResource, theEventWriter, theObjectNameOrNull, theIsSubElementWithinResource, resourceId);
} }
private void encodeResourceToJsonStreamWriter(RuntimeResourceDefinition theResDef, IBaseResource theResource, JsonGenerator theEventWriter, String theObjectNameOrNull, private void encodeResourceToJsonStreamWriter(RuntimeResourceDefinition theResDef, IBaseResource theResource, JsonGenerator theEventWriter, String theObjectNameOrNull, boolean theIsSubElementWithinResource, String theResourceId) throws IOException {
boolean theIsSubElementWithinResource, String theResourceId) throws IOException {
if (!theIsSubElementWithinResource) { if (!theIsSubElementWithinResource) {
super.containResourcesForEncoding(theResource); super.containResourcesForEncoding(theResource);
} }
@ -599,10 +603,12 @@ public class JsonParser extends BaseParser implements IParser {
if (myContext.getVersion().getVersion().isNewerThan(FhirVersionEnum.DSTU1) && theResource instanceof IResource) { if (myContext.getVersion().getVersion().isNewerThan(FhirVersionEnum.DSTU1) && theResource instanceof IResource) {
IResource resource = (IResource) theResource; IResource resource = (IResource) theResource;
theEventWriter.writeStartObject("meta"); if (!ElementUtil.isEmpty(resource.getId().getVersionIdPart(), ResourceMetadataKeyEnum.UPDATED.get(resource))) {
writeOptionalTagWithTextNode(theEventWriter, "versionId", resource.getId().getVersionIdPart()); theEventWriter.writeStartObject("meta");
writeOptionalTagWithTextNode(theEventWriter, "lastUpdated", ResourceMetadataKeyEnum.UPDATED.get(resource)); writeOptionalTagWithTextNode(theEventWriter, "versionId", resource.getId().getVersionIdPart());
theEventWriter.writeEnd(); writeOptionalTagWithTextNode(theEventWriter, "lastUpdated", ResourceMetadataKeyEnum.UPDATED.get(resource));
theEventWriter.writeEnd();
}
} }
if (theResource instanceof Binary) { if (theResource instanceof Binary) {
@ -657,10 +663,10 @@ public class JsonParser extends BaseParser implements IParser {
} }
/** /**
* This is useful only for the two cases where extensions are encoded as direct children (e.g. not in some object called _name): resource extensions, and extension extensions * This is useful only for the two cases where extensions are encoded as direct children (e.g. not in some object
* called _name): resource extensions, and extension extensions
*/ */
private void extractAndWriteExtensionsAsDirectChild(IBase theElement, JsonGenerator theEventWriter, BaseRuntimeElementDefinition<?> theElementDef, RuntimeResourceDefinition theResDef, private void extractAndWriteExtensionsAsDirectChild(IBase theElement, JsonGenerator theEventWriter, BaseRuntimeElementDefinition<?> theElementDef, RuntimeResourceDefinition theResDef, IBaseResource theResource, String theParentExtensionUrl) throws IOException {
IBaseResource theResource) throws IOException {
List<HeldExtension> extensions = new ArrayList<HeldExtension>(0); List<HeldExtension> extensions = new ArrayList<HeldExtension>(0);
List<HeldExtension> modifierExtensions = new ArrayList<HeldExtension>(0); List<HeldExtension> modifierExtensions = new ArrayList<HeldExtension>(0);
@ -668,10 +674,12 @@ public class JsonParser extends BaseParser implements IParser {
extractUndeclaredExtensions(theElement, extensions, modifierExtensions); extractUndeclaredExtensions(theElement, extensions, modifierExtensions);
// Declared extensions // Declared extensions
extractDeclaredExtensions(theElement, theElementDef, extensions, modifierExtensions); if (theElementDef != null) {
extractDeclaredExtensions(theElement, theElementDef, extensions, modifierExtensions);
}
// Write the extensions // Write the extensions
writeExtensionsAsDirectChild(theResource, theEventWriter, theResDef, extensions, modifierExtensions); writeExtensionsAsDirectChild(theResource, theEventWriter, theResDef, extensions, modifierExtensions, theParentExtensionUrl);
} }
private void extractDeclaredExtensions(IBase theResource, BaseRuntimeElementDefinition<?> resDef, List<HeldExtension> extensions, List<HeldExtension> modifierExtensions) { private void extractDeclaredExtensions(IBase theResource, BaseRuntimeElementDefinition<?> resDef, List<HeldExtension> extensions, List<HeldExtension> modifierExtensions) {
@ -721,15 +729,17 @@ public class JsonParser extends BaseParser implements IParser {
if (theAlternateVal == null || theAlternateVal.getValueType() == ValueType.NULL) { if (theAlternateVal == null || theAlternateVal.getValueType() == ValueType.NULL) {
return; return;
} }
boolean newerThanDstu1 = myContext.getVersion().getVersion().isNewerThan(FhirVersionEnum.DSTU1);
JsonObject alternate = (JsonObject) theAlternateVal; JsonObject alternate = (JsonObject) theAlternateVal;
for (Entry<String, JsonValue> nextEntry : alternate.entrySet()) { for (Entry<String, JsonValue> nextEntry : alternate.entrySet()) {
String nextKey = nextEntry.getKey(); String nextKey = nextEntry.getKey();
JsonValue nextVal = nextEntry.getValue(); JsonValue nextVal = nextEntry.getValue();
if ("extension".equals(nextKey)) { if (!newerThanDstu1 && "extension".equals(nextKey)) {
boolean isModifier = false; boolean isModifier = false;
JsonArray array = (JsonArray) nextEntry.getValue(); JsonArray array = (JsonArray) nextEntry.getValue();
parseExtension(theState, array, isModifier); parseExtension(theState, array, isModifier);
} else if ("modifierExtension".equals(nextKey)) { } else if (!newerThanDstu1 && "modifierExtension".equals(nextKey)) {
boolean isModifier = true; boolean isModifier = true;
JsonArray array = (JsonArray) nextEntry.getValue(); JsonArray array = (JsonArray) nextEntry.getValue();
parseExtension(theState, array, isModifier); parseExtension(theState, array, isModifier);
@ -743,6 +753,12 @@ public class JsonParser extends BaseParser implements IParser {
default: default:
break; break;
} }
} else if (newerThanDstu1) {
if (nextKey.indexOf(':') > -1 && newerThanDstu1) {
JsonArray array = (JsonArray) nextEntry.getValue();
parseExtensionInDstu2Style(false, theState, null, nextKey, array);
continue;
}
} }
} }
} }
@ -757,8 +773,7 @@ public class JsonParser extends BaseParser implements IParser {
object = reader.readObject(); object = reader.readObject();
} catch (JsonParsingException e) { } catch (JsonParsingException e) {
if (e.getMessage().startsWith("Unexpected char 39")) { if (e.getMessage().startsWith("Unexpected char 39")) {
throw new DataFormatException("Failed to parse JSON encoded FHIR content: " + e.getMessage() throw new DataFormatException("Failed to parse JSON encoded FHIR content: " + e.getMessage() + " - This may indicate that single quotes are being used as JSON escapes where double quotes are required", e);
+ " - This may indicate that single quotes are being used as JSON escapes where double quotes are required", e);
} }
throw new DataFormatException("Failed to parse JSON encoded FHIR content: " + e.getMessage(), e); throw new DataFormatException("Failed to parse JSON encoded FHIR content: " + e.getMessage(), e);
} }
@ -861,6 +876,7 @@ public class JsonParser extends BaseParser implements IParser {
private void parseChildren(JsonObject theObject, ParserState<?> theState) { private void parseChildren(JsonObject theObject, ParserState<?> theState) {
String elementId = null; String elementId = null;
boolean newerThanDstu1 = myContext.getVersion().getVersion().isNewerThan(FhirVersionEnum.DSTU1);
for (String nextName : theObject.keySet()) { for (String nextName : theObject.keySet()) {
if ("resourceType".equals(nextName)) { if ("resourceType".equals(nextName)) {
continue; continue;
@ -873,19 +889,29 @@ public class JsonParser extends BaseParser implements IParser {
// _id is incorrect, but some early examples in the FHIR spec used it // _id is incorrect, but some early examples in the FHIR spec used it
elementId = theObject.getString(nextName); elementId = theObject.getString(nextName);
continue; continue;
} else if ("extension".equals(nextName)) { } else if (!newerThanDstu1 && "extension".equals(nextName)) {
JsonArray array = theObject.getJsonArray(nextName); JsonArray array = theObject.getJsonArray(nextName);
parseExtension(theState, array, false); parseExtension(theState, array, false);
continue; continue;
} else if ("modifierExtension".equals(nextName)) { } else if (!newerThanDstu1 && "modifierExtension".equals(nextName)) {
JsonArray array = theObject.getJsonArray(nextName); JsonArray array = theObject.getJsonArray(nextName);
parseExtension(theState, array, true); parseExtension(theState, array, true);
continue; continue;
} else if (newerThanDstu1 && "modifier".equals(nextName)) {
JsonObject obj = theObject.getJsonObject(nextName);
for (String nextUrl : obj.keySet()) {
JsonArray array = obj.getJsonArray(nextUrl);
parseExtensionInDstu2Style(true, theState, null, nextUrl, array);
}
continue;
} else if (nextName.charAt(0) == '_') { } else if (nextName.charAt(0) == '_') {
continue; continue;
} else if (nextName.contains(":") && myContext.getVersion().getVersion().isNewerThan(FhirVersionEnum.DSTU1)) { } else {
JsonArray array = theObject.getJsonArray(nextName); if (newerThanDstu1 && nextName.indexOf(':') > -1) {
parseExtensionInDstu2Style(theState, nextName, array); JsonArray array = theObject.getJsonArray(nextName);
parseExtensionInDstu2Style(false, theState, null, nextName, array);
continue;
}
} }
JsonValue nextVal = theObject.get(nextName); JsonValue nextVal = theObject.get(nextName);
@ -905,7 +931,6 @@ public class JsonParser extends BaseParser implements IParser {
} }
} }
private void parseChildren(ParserState<?> theState, String theName, JsonValue theJsonVal, JsonValue theAlternateVal) { private void parseChildren(ParserState<?> theState, String theName, JsonValue theJsonVal, JsonValue theAlternateVal) {
switch (theJsonVal.getValueType()) { switch (theJsonVal.getValueType()) {
case ARRAY: { case ARRAY: {
@ -985,17 +1010,30 @@ public class JsonParser extends BaseParser implements IParser {
theState.endingElement(); theState.endingElement();
} }
} }
private void parseExtensionInDstu2Style(ParserState<?> theState, String theUrl, JsonArray theValues) { private void parseExtensionInDstu2Style(boolean theModifier, ParserState<?> theState, String theParentExtensionUrl, String theExtensionUrl, JsonArray theValues) {
theState.enteringNewElementExtension(null, theUrl, false); String extUrl = UrlUtil.constructAbsoluteUrl(theParentExtensionUrl, theExtensionUrl);
theState.enteringNewElementExtension(null, extUrl, theModifier);
for (int extIdx = 0; extIdx < theValues.size(); extIdx++) { for (int extIdx = 0; extIdx < theValues.size(); extIdx++) {
JsonObject nextExt = theValues.getJsonObject(extIdx); JsonObject nextExt = theValues.getJsonObject(extIdx);
for (String nextKey : nextExt.keySet()) { for (String nextKey : nextExt.keySet()) {
if (nextKey.startsWith("value") && nextKey.length() > 5 && ) // if (nextKey.startsWith("value") && nextKey.length() > 5 &&
// myContext.getRuntimeChildUndeclaredExtensionDefinition().getChildByName(nextKey) != null) {
JsonValue jsonVal = nextExt.get(nextKey);
if (jsonVal.getValueType() == ValueType.ARRAY) {
/*
* Extension children which are arrays are sub-extensions. Any other value type should be treated as
* a value.
*/
JsonArray arrayValue = (JsonArray) jsonVal;
parseExtensionInDstu2Style(theModifier, theState, extUrl, nextKey, arrayValue);
} else {
parseChildren(theState, nextKey, jsonVal, null);
}
} }
} }
theState.endingElement(); theState.endingElement();
} }
@ -1015,7 +1053,7 @@ public class JsonParser extends BaseParser implements IParser {
def = myContext.getResourceDefinition(resourceType); def = myContext.getResourceDefinition(resourceType);
} }
ParserState<? extends IResource> state = (ParserState<? extends IResource>) ParserState.getPreResourceInstance(def.getImplementingClass(), myContext, true); ParserState<? extends IBaseResource> state = (ParserState<? extends IBaseResource>) ParserState.getPreResourceInstance(def.getImplementingClass(), myContext, true);
state.enteringNewElement(null, def.getName()); state.enteringNewElement(null, def.getName());
parseChildren(object, state); parseChildren(object, state);
@ -1115,21 +1153,44 @@ public class JsonParser extends BaseParser implements IParser {
} }
} }
private void writeExtensionsAsDirectChild(IBaseResource theResource, JsonGenerator theEventWriter, RuntimeResourceDefinition resDef, List<HeldExtension> extensions, private void writeExtensionsAsDirectChild(IBaseResource theResource, JsonGenerator theEventWriter, RuntimeResourceDefinition resDef, List<HeldExtension> extensions, List<HeldExtension> modifierExtensions, String theParentExtensionUrl) throws IOException {
List<HeldExtension> modifierExtensions) throws IOException {
if (extensions.isEmpty() == false) { if (extensions.isEmpty() == false) {
theEventWriter.writeStartArray("extension"); if (myContext.getVersion().getVersion().isNewerThan(FhirVersionEnum.DSTU1)) {
for (HeldExtension next : extensions) { Collections.sort(extensions);
next.write(resDef, theResource, theEventWriter); String currentlyWritingExtensionUrl = null;
for (HeldExtension next : extensions) {
currentlyWritingExtensionUrl = next.writeExtensionInDstu2Format(resDef, theResource, theEventWriter, currentlyWritingExtensionUrl, theParentExtensionUrl);
}
if (currentlyWritingExtensionUrl != null) {
theEventWriter.writeEnd();
}
} else {
theEventWriter.writeStartArray("extension");
for (HeldExtension next : extensions) {
next.write(resDef, theResource, theEventWriter);
}
theEventWriter.writeEnd();
} }
theEventWriter.writeEnd();
} }
if (modifierExtensions.isEmpty() == false) { if (modifierExtensions.isEmpty() == false) {
theEventWriter.writeStartArray("modifierExtension"); if (myContext.getVersion().getVersion().isNewerThan(FhirVersionEnum.DSTU1)) {
for (HeldExtension next : modifierExtensions) { Collections.sort(modifierExtensions);
next.write(resDef, theResource, theEventWriter); theEventWriter.writeStartObject("modifier");
String currentlyWritingExtensionUrl = null;
for (HeldExtension next : modifierExtensions) {
currentlyWritingExtensionUrl = next.writeExtensionInDstu2Format(resDef, theResource, theEventWriter, currentlyWritingExtensionUrl, theParentExtensionUrl);
}
if (currentlyWritingExtensionUrl != null) {
theEventWriter.writeEnd();
}
theEventWriter.writeEnd();
} else {
theEventWriter.writeStartArray("modifierExtension");
for (HeldExtension next : modifierExtensions) {
next.write(resDef, theResource, theEventWriter);
}
theEventWriter.writeEnd();
} }
theEventWriter.writeEnd();
} }
} }
@ -1184,7 +1245,7 @@ public class JsonParser extends BaseParser implements IParser {
// } // }
} }
private class HeldExtension { private class HeldExtension implements Comparable<HeldExtension> {
private RuntimeChildDeclaredExtensionDefinition myDef; private RuntimeChildDeclaredExtensionDefinition myDef;
private ExtensionDt myUndeclaredExtension; private ExtensionDt myUndeclaredExtension;
@ -1204,41 +1265,73 @@ public class JsonParser extends BaseParser implements IParser {
public void write(RuntimeResourceDefinition theResDef, IBaseResource theResource, JsonGenerator theEventWriter) throws IOException { public void write(RuntimeResourceDefinition theResDef, IBaseResource theResource, JsonGenerator theEventWriter) throws IOException {
if (myUndeclaredExtension != null) { if (myUndeclaredExtension != null) {
writeUndeclaredExt(theResDef, theResource, theEventWriter, myUndeclaredExtension); writeUndeclaredExtInDstu1Format(theResDef, theResource, theEventWriter, myUndeclaredExtension);
} else { } else {
theEventWriter.writeStartObject(); theEventWriter.writeStartObject();
theEventWriter.write("url", myDef.getExtensionUrl()); theEventWriter.write("url", myDef.getExtensionUrl());
BaseRuntimeElementDefinition<?> def = myDef.getChildElementDefinitionByDatatype(myValue.getClass()); BaseRuntimeElementDefinition<?> def = myDef.getChildElementDefinitionByDatatype(myValue.getClass());
if (def.getChildType() == ChildTypeEnum.RESOURCE_BLOCK) { if (def.getChildType() == ChildTypeEnum.RESOURCE_BLOCK) {
extractAndWriteExtensionsAsDirectChild(myValue, theEventWriter, def, theResDef, theResource); extractAndWriteExtensionsAsDirectChild(myValue, theEventWriter, def, theResDef, theResource, myDef.getExtensionUrl());
} else { } else {
// encodeChildElementToStreamWriter(theResDef, theResource,
// theEventWriter, myValue, def, "value" +
// WordUtils.capitalize(def.getName()));
String childName = myDef.getChildNameByDatatype(myValue.getClass()); String childName = myDef.getChildNameByDatatype(myValue.getClass());
encodeChildElementToStreamWriter(theResDef, theResource, theEventWriter, myValue, def, childName, false); encodeChildElementToStreamWriter(theResDef, theResource, theEventWriter, myValue, def, childName, false);
} }
// theEventWriter.name(myUndeclaredExtension.get);
theEventWriter.writeEnd(); theEventWriter.writeEnd();
} }
} }
private void writeUndeclaredExt(RuntimeResourceDefinition theResDef, IBaseResource theResource, JsonGenerator theEventWriter, ExtensionDt ext) throws IOException { public String writeExtensionInDstu2Format(RuntimeResourceDefinition theResDef, IBaseResource theResource, JsonGenerator theEventWriter, String theCurrentlyWritingExtensionUrl, String theParentExtensionUrl) throws IOException {
IElement value = ext.getValue(); if (myUndeclaredExtension != null) {
return writeUndeclaredExtInDstu2Format(theResDef, theResource, theEventWriter, myUndeclaredExtension, theCurrentlyWritingExtensionUrl, theParentExtensionUrl);
} else {
String extensionUrl = myDef.getExtensionUrl();
checkIfNewExtensionUrlArrayIsNeeded(theEventWriter, extensionUrl, theCurrentlyWritingExtensionUrl, theParentExtensionUrl);
theEventWriter.writeStartObject();
theEventWriter.writeStartObject(); BaseRuntimeElementDefinition<?> def = myDef.getChildElementDefinitionByDatatype(myValue.getClass());
theEventWriter.write("url", ext.getUrl().getValue()); if (def.getChildType() == ChildTypeEnum.RESOURCE_BLOCK) {
extractAndWriteExtensionsAsDirectChild(myValue, theEventWriter, def, theResDef, theResource, extensionUrl);
} else {
String childName = myDef.getChildNameByDatatype(myValue.getClass());
encodeChildElementToStreamWriter(theResDef, theResource, theEventWriter, myValue, def, childName, false);
}
theEventWriter.writeEnd();
return extensionUrl;
}
}
private void checkIfNewExtensionUrlArrayIsNeeded(JsonGenerator theEventWriter, String theExtensionUrl, String theCurrentlyWritingExtensionUrl, String theParentExtensionUrl) {
if (StringUtils.equals(theCurrentlyWritingExtensionUrl, theExtensionUrl)==false) {
if (isNotBlank(theCurrentlyWritingExtensionUrl)) {
theEventWriter.writeEnd();
}
String urlToWrite = UrlUtil.constructRelativeUrl(theParentExtensionUrl, theExtensionUrl);
theEventWriter.writeStartArray(urlToWrite);
}
}
private void writeUndeclaredExtInDstu1Format(RuntimeResourceDefinition theResDef, IBaseResource theResource, JsonGenerator theEventWriter, ExtensionDt ext) throws IOException {
IElement value = ext.getValue();
String extensionUrl = ext.getUrl().getValue();
theEventWriter.writeStartObject();
theEventWriter.write("url", extensionUrl);
boolean noValue = value == null || value.isEmpty(); boolean noValue = value == null || value.isEmpty();
if (noValue && ext.getAllUndeclaredExtensions().isEmpty()) { if (noValue && ext.getAllUndeclaredExtensions().isEmpty()) {
ourLog.debug("Extension with URL[{}] has no value", ext.getUrl().getValue()); ourLog.debug("Extension with URL[{}] has no value", extensionUrl);
} else if (noValue) { } else if (noValue) {
theEventWriter.writeStartArray("extension");
theEventWriter.writeStartArray("extension");
for (ExtensionDt next : ext.getUndeclaredExtensions()) { for (ExtensionDt next : ext.getUndeclaredExtensions()) {
writeUndeclaredExt(theResDef, theResource, theEventWriter, next); writeUndeclaredExtInDstu1Format(theResDef, theResource, theEventWriter, next);
} }
theEventWriter.writeEnd(); theEventWriter.writeEnd();
} else { } else {
@ -1256,5 +1349,45 @@ public class JsonParser extends BaseParser implements IParser {
theEventWriter.writeEnd(); theEventWriter.writeEnd();
} }
private String writeUndeclaredExtInDstu2Format(RuntimeResourceDefinition theResDef, IBaseResource theResource, JsonGenerator theEventWriter, ExtensionDt ext, String theCurrentlyWritingExtensionUrl, String theParentExtensionUrl) throws IOException {
IElement value = ext.getValue();
String extensionUrl = ext.getUrl().getValue();
checkIfNewExtensionUrlArrayIsNeeded(theEventWriter, extensionUrl, theCurrentlyWritingExtensionUrl, theParentExtensionUrl);
theEventWriter.writeStartObject();
boolean noValue = value == null || value.isEmpty();
if (noValue && ext.getAllUndeclaredExtensions().isEmpty()) {
ourLog.debug("Extension with URL[{}] has no value", extensionUrl);
} else if (noValue) {
BaseRuntimeElementDefinition<?> elemDef = null;
RuntimeResourceDefinition resDef = myContext.getResourceDefinition(theResource);
extractAndWriteExtensionsAsDirectChild(ext, theEventWriter, elemDef, resDef, theResource, extensionUrl);
} else {
RuntimeChildUndeclaredExtensionDefinition extDef = myContext.getRuntimeChildUndeclaredExtensionDefinition();
String childName = extDef.getChildNameByDatatype(value.getClass());
if (childName == null) {
throw new ConfigurationException("Unable to encode extension, unregognized child element type: " + value.getClass().getCanonicalName());
}
BaseRuntimeElementDefinition<?> childDef = extDef.getChildElementDefinitionByDatatype(value.getClass());
encodeChildElementToStreamWriter(theResDef, theResource, theEventWriter, value, childDef, childName, true);
}
theEventWriter.writeEnd();
return extensionUrl;
}
@Override
public int compareTo(HeldExtension theArg0) {
String url1 = myDef != null ? myDef.getExtensionUrl() : myUndeclaredExtension.getUrlAsString();
String url2 = theArg0.myDef != null ? theArg0.myDef.getExtensionUrl() : theArg0.myUndeclaredExtension.getUrlAsString();
url1 = defaultString(url1);
url2 = defaultString(url2);
return url1.compareTo(url2);
}
} }
} }

View File

@ -1,5 +1,8 @@
package ca.uhn.fhir.util; package ca.uhn.fhir.util;
import java.net.MalformedURLException;
import java.net.URL;
/* /*
* #%L * #%L
* HAPI FHIR - Core Library * HAPI FHIR - Core Library
@ -21,10 +24,64 @@ package ca.uhn.fhir.util;
*/ */
public class UrlUtil { public class UrlUtil {
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(UrlUtil.class);
/**
* Resolve a relative URL - THIS METHOD WILL NOT FAIL but will log a warning
* and return theEndpoint if the input is invalid.
*/
public static String constructAbsoluteUrl(String theBase, String theEndpoint) {
if (theEndpoint == null) {
return null;
}
if (isAbsolute(theEndpoint)) {
return theEndpoint;
}
if (theBase == null) {
return theEndpoint;
}
try {
return new URL(new URL(theBase), theEndpoint).toString();
} catch (MalformedURLException e) {
ourLog.warn("Failed to resolve relative URL[" + theEndpoint + "] against absolute base[" + theBase + "]", e);
return theEndpoint;
}
}
public static boolean isAbsolute(String theValue) { public static boolean isAbsolute(String theValue) {
String value = theValue.toLowerCase(); String value = theValue.toLowerCase();
return value.startsWith("http://") || value.startsWith("https://"); return value.startsWith("http://") || value.startsWith("https://");
} }
public static String constructRelativeUrl(String theParentExtensionUrl, String theExtensionUrl) {
if (theParentExtensionUrl == null) {
return theExtensionUrl;
}
if (theExtensionUrl == null) {
return theExtensionUrl;
}
int parentLastSlashIdx = theParentExtensionUrl.lastIndexOf('/');
int childLastSlashIdx = theExtensionUrl.lastIndexOf('/');
if (parentLastSlashIdx == -1 || childLastSlashIdx == -1) {
return theExtensionUrl;
}
if (parentLastSlashIdx != childLastSlashIdx) {
return theExtensionUrl;
}
if (!theParentExtensionUrl.substring(0, parentLastSlashIdx).equals(theExtensionUrl.substring(0, parentLastSlashIdx))) {
return theExtensionUrl;
}
if (theExtensionUrl.length() > parentLastSlashIdx) {
return theExtensionUrl.substring(parentLastSlashIdx+1);
}
return theExtensionUrl;
}
} }

View File

@ -0,0 +1,29 @@
package ca.uhn.fhir.util;
import static org.junit.Assert.*;
import org.junit.Test;
public class UrlUtilTest {
@Test
public void testConstructAbsoluteUrl() {
assertEquals("http://foo/bar/baz", UrlUtil.constructAbsoluteUrl(null, "http://foo/bar/baz"));
assertEquals("http://foo/bar/baz", UrlUtil.constructAbsoluteUrl("http://foo/bar/","baz"));
assertEquals("http://foo/bar/baz/", UrlUtil.constructAbsoluteUrl("http://foo/bar/","baz/"));
assertEquals("http://foo/bar/baz/", UrlUtil.constructAbsoluteUrl("http://foo/bar/","./baz/"));
assertEquals("http://foo/baz/", UrlUtil.constructAbsoluteUrl("http://foo/bar/","../baz/"));
assertEquals("http://foo/baz/", UrlUtil.constructAbsoluteUrl("http://foo/bar/","/baz/"));
}
@Test
public void testConstructRelativeUrl() {
assertEquals("http://foo/bar/baz", UrlUtil.constructRelativeUrl("http://boo/far/faz", "http://foo/bar/baz"));
assertEquals("http://foo/bar/baz", UrlUtil.constructRelativeUrl("http://foo/far/faz", "http://foo/bar/baz"));
assertEquals("baz", UrlUtil.constructRelativeUrl("http://foo/bar/boo", "http://foo/bar/baz"));
}
}

View File

@ -33,6 +33,7 @@ import javax.persistence.criteria.Root;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.Validate; import org.apache.commons.lang3.Validate;
import org.apache.commons.lang3.tuple.Pair; import org.apache.commons.lang3.tuple.Pair;
import org.hl7.fhir.instance.model.IBaseResource;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.PlatformTransactionManager; import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionStatus; import org.springframework.transaction.TransactionStatus;
@ -117,7 +118,7 @@ public abstract class BaseFhirDao implements IDao {
@Autowired @Autowired
private List<IFhirResourceDao<?>> myResourceDaos; private List<IFhirResourceDao<?>> myResourceDaos;
private Map<Class<? extends IResource>, IFhirResourceDao<?>> myResourceTypeToDao; private Map<Class<? extends IBaseResource>,IFhirResourceDao<?>> myResourceTypeToDao;
public FhirContext getContext() { public FhirContext getContext() {
return myContext; return myContext;
@ -343,7 +344,7 @@ public abstract class BaseFhirDao implements IDao {
if (isBlank(typeString)) { if (isBlank(typeString)) {
throw new InvalidRequestException("Invalid resource reference found at path[" + nextPathsUnsplit + "] - Does not contain resource type - " + nextValue.getReference().getValue()); throw new InvalidRequestException("Invalid resource reference found at path[" + nextPathsUnsplit + "] - Does not contain resource type - " + nextValue.getReference().getValue());
} }
Class<? extends IResource> type = getContext().getResourceDefinition(typeString).getImplementingClass(); Class<? extends IBaseResource> type = getContext().getResourceDefinition(typeString).getImplementingClass();
String id = nextValue.getReference().getIdPart(); String id = nextValue.getReference().getIdPart();
if (StringUtils.isBlank(id)) { if (StringUtils.isBlank(id)) {
continue; continue;
@ -798,9 +799,9 @@ public abstract class BaseFhirDao implements IDao {
return myConfig; return myConfig;
} }
protected IFhirResourceDao<? extends IResource> getDao(Class<? extends IResource> theType) { protected IFhirResourceDao<? extends IResource> getDao(Class<? extends IBaseResource> theType) {
if (myResourceTypeToDao == null) { if (myResourceTypeToDao == null) {
myResourceTypeToDao = new HashMap<Class<? extends IResource>, IFhirResourceDao<?>>(); myResourceTypeToDao = new HashMap<Class<? extends IBaseResource>, IFhirResourceDao<?>>();
for (IFhirResourceDao<?> next : myResourceDaos) { for (IFhirResourceDao<?> next : myResourceDaos) {
myResourceTypeToDao.put(next.getResourceType(), next); myResourceTypeToDao.put(next.getResourceType(), next);
} }
@ -928,7 +929,7 @@ public abstract class BaseFhirDao implements IDao {
ArrayList<IResource> retVal = new ArrayList<IResource>(); ArrayList<IResource> retVal = new ArrayList<IResource>();
for (BaseHasResource next : resEntities) { for (BaseHasResource next : resEntities) {
retVal.add(toResource(next)); retVal.add((IResource) toResource(next));
} }
return retVal; return retVal;
} }
@ -971,7 +972,7 @@ public abstract class BaseFhirDao implements IDao {
ArrayList<IResource> retVal = new ArrayList<IResource>(); ArrayList<IResource> retVal = new ArrayList<IResource>();
for (ResourceTable next : q.getResultList()) { for (ResourceTable next : q.getResultList()) {
IResource resource = toResource(next); IResource resource = (IResource) toResource(next);
retVal.add(resource); retVal.add(resource);
} }
@ -1056,12 +1057,12 @@ public abstract class BaseFhirDao implements IDao {
return retVal; return retVal;
} }
protected IResource toResource(BaseHasResource theEntity) { protected IBaseResource toResource(BaseHasResource theEntity) {
RuntimeResourceDefinition type = myContext.getResourceDefinition(theEntity.getResourceType()); RuntimeResourceDefinition type = myContext.getResourceDefinition(theEntity.getResourceType());
return toResource(type.getImplementingClass(), theEntity); return toResource(type.getImplementingClass(), theEntity);
} }
protected <T extends IResource> T toResource(Class<T> theResourceType, BaseHasResource theEntity) { protected <T extends IBaseResource> T toResource(Class<T> theResourceType, BaseHasResource theEntity) {
String resourceText = null; String resourceText = null;
switch (theEntity.getEncoding()) { switch (theEntity.getEncoding()) {
case JSON: case JSON:
@ -1079,18 +1080,19 @@ public abstract class BaseFhirDao implements IDao {
IParser parser = theEntity.getEncoding().newParser(getContext()); IParser parser = theEntity.getEncoding().newParser(getContext());
T retVal = parser.parseResource(theResourceType, resourceText); T retVal = parser.parseResource(theResourceType, resourceText);
retVal.setId(theEntity.getIdDt()); IResource res = (IResource)retVal;
res.setId(theEntity.getIdDt());
retVal.getResourceMetadata().put(ResourceMetadataKeyEnum.VERSION_ID, theEntity.getVersion()); res.getResourceMetadata().put(ResourceMetadataKeyEnum.VERSION_ID, theEntity.getVersion());
retVal.getResourceMetadata().put(ResourceMetadataKeyEnum.PUBLISHED, theEntity.getPublished()); res.getResourceMetadata().put(ResourceMetadataKeyEnum.PUBLISHED, theEntity.getPublished());
retVal.getResourceMetadata().put(ResourceMetadataKeyEnum.UPDATED, theEntity.getUpdated()); res.getResourceMetadata().put(ResourceMetadataKeyEnum.UPDATED, theEntity.getUpdated());
if (theEntity.getTitle() != null) { if (theEntity.getTitle() != null) {
ResourceMetadataKeyEnum.TITLE.put(retVal, theEntity.getTitle()); ResourceMetadataKeyEnum.TITLE.put(res, theEntity.getTitle());
} }
if (theEntity.getDeleted() != null) { if (theEntity.getDeleted() != null) {
ResourceMetadataKeyEnum.DELETED_AT.put(retVal, new InstantDt(theEntity.getDeleted())); ResourceMetadataKeyEnum.DELETED_AT.put(res, new InstantDt(theEntity.getDeleted()));
} }
Collection<? extends BaseTag> tags = theEntity.getTags(); Collection<? extends BaseTag> tags = theEntity.getTags();
@ -1099,8 +1101,9 @@ public abstract class BaseFhirDao implements IDao {
for (BaseTag next : tags) { for (BaseTag next : tags) {
tagList.add(new Tag(next.getTag().getScheme(), next.getTag().getTerm(), next.getTag().getLabel())); tagList.add(new Tag(next.getTag().getScheme(), next.getTag().getTerm(), next.getTag().getLabel()));
} }
retVal.getResourceMetadata().put(ResourceMetadataKeyEnum.TAG_LIST, tagList); res.getResourceMetadata().put(ResourceMetadataKeyEnum.TAG_LIST, tagList);
} }
return retVal; return retVal;
} }

View File

@ -32,6 +32,7 @@ import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root; import javax.persistence.criteria.Root;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.hl7.fhir.instance.model.IBaseResource;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Required; import org.springframework.beans.factory.annotation.Required;
import org.springframework.transaction.PlatformTransactionManager; import org.springframework.transaction.PlatformTransactionManager;
@ -1125,16 +1126,16 @@ public class FhirResourceDao<T extends IResource> extends BaseFhirDao implements
if (!(def instanceof RuntimeChildResourceDefinition)) { if (!(def instanceof RuntimeChildResourceDefinition)) {
throw new ConfigurationException("Property " + chain + " of type " + myResourceName + " is not a resource: " + def.getClass()); throw new ConfigurationException("Property " + chain + " of type " + myResourceName + " is not a resource: " + def.getClass());
} }
List<Class<? extends IResource>> resourceTypes; List<Class<? extends IBaseResource>> resourceTypes;
if (isBlank(ref.getResourceType())) { if (isBlank(ref.getResourceType())) {
RuntimeChildResourceDefinition resDef = (RuntimeChildResourceDefinition) def; RuntimeChildResourceDefinition resDef = (RuntimeChildResourceDefinition) def;
resourceTypes = resDef.getResourceTypes(); resourceTypes = resDef.getResourceTypes();
} else { } else {
resourceTypes = new ArrayList<Class<? extends IResource>>(); resourceTypes = new ArrayList<Class<? extends IBaseResource>>();
RuntimeResourceDefinition resDef = getContext().getResourceDefinition(ref.getResourceType()); RuntimeResourceDefinition resDef = getContext().getResourceDefinition(ref.getResourceType());
resourceTypes.add(resDef.getImplementingClass()); resourceTypes.add(resDef.getImplementingClass());
} }
for (Class<? extends IResource> nextType : resourceTypes) { for (Class<? extends IBaseResource> nextType : resourceTypes) {
RuntimeResourceDefinition typeDef = getContext().getResourceDefinition(nextType); RuntimeResourceDefinition typeDef = getContext().getResourceDefinition(nextType);
RuntimeSearchParam param = typeDef.getSearchParam(ref.getChain()); RuntimeSearchParam param = typeDef.getSearchParam(ref.getChain());
if (param == null) { if (param == null) {

View File

@ -1,3 +1,4 @@
myUnitTestDB/ myUnitTestDB/
target/ target/
/bin /bin
/target/

View File

@ -336,6 +336,17 @@
</plugin> </plugin>
</plugins> </plugins>
</pluginManagement> </pluginManagement>
<resources>
<resource>
<directory>${baseDir}/src/main/resources</directory>
</resource>
<resource>
<directory>${baseDir}/target/generated-sources/tinder</directory>
</resource>
<resource>
<directory>${baseDir}/target/generated-resources/tinder</directory>
</resource>
</resources>
</build> </build>
<reporting> <reporting>

View File

@ -3,6 +3,7 @@ package ca.uhn.fhir.parser;
import static org.junit.Assert.*; import static org.junit.Assert.*;
import net.sf.json.JSON; import net.sf.json.JSON;
import net.sf.json.JSONSerializer; import net.sf.json.JSONSerializer;
import net.sf.json.JsonConfig;
import org.apache.commons.io.IOUtils; import org.apache.commons.io.IOUtils;
import org.junit.Test; import org.junit.Test;
@ -13,8 +14,11 @@ import ca.uhn.fhir.model.api.ExtensionDt;
import ca.uhn.fhir.model.api.ResourceMetadataKeyEnum; import ca.uhn.fhir.model.api.ResourceMetadataKeyEnum;
import ca.uhn.fhir.model.dev.resource.MedicationPrescription; import ca.uhn.fhir.model.dev.resource.MedicationPrescription;
import ca.uhn.fhir.model.dev.resource.Patient; import ca.uhn.fhir.model.dev.resource.Patient;
import ca.uhn.fhir.model.dstu.resource.Binary;
import ca.uhn.fhir.model.primitive.BooleanDt;
import ca.uhn.fhir.model.primitive.CodeDt; import ca.uhn.fhir.model.primitive.CodeDt;
import ca.uhn.fhir.model.primitive.DateDt; import ca.uhn.fhir.model.primitive.DateDt;
import ca.uhn.fhir.model.primitive.IdDt;
import ca.uhn.fhir.model.primitive.InstantDt; import ca.uhn.fhir.model.primitive.InstantDt;
public class JsonParserTest { public class JsonParserTest {
@ -23,7 +27,13 @@ public class JsonParserTest {
@Test @Test
public void testParseBundleWithBinary() { public void testParseBundleWithBinary() {
// TODO: implement this test, make sure we handle ID and meta correctly in Binary Binary patient = new Binary();
patient.setId(new IdDt("http://base/Binary/11/_history/22"));
patient.setContentType("foo");
patient.setContent(new byte[] { 1, 2, 3, 4 });
String val = ourCtx.newJsonParser().encodeResourceToString(patient);
assertEquals("{\"resourceType\":\"Binary\",\"id\":\"11\",\"meta\":{\"versionId\":\"22\"},\"contentType\":\"foo\",\"content\":\"AQIDBA==\"}", val);
} }
@Test @Test
@ -52,8 +62,10 @@ public class JsonParserTest {
String reencoded = ourCtx.newJsonParser().setPrettyPrint(true).encodeBundleToString(parsed); String reencoded = ourCtx.newJsonParser().setPrettyPrint(true).encodeBundleToString(parsed);
ourLog.info(reencoded); ourLog.info(reencoded);
JSON expected = JSONSerializer.toJSON(content.trim()); JsonConfig cfg = new JsonConfig();
JSON actual = JSONSerializer.toJSON(reencoded.trim());
JSON expected = JSONSerializer.toJSON(content.trim(), cfg);
JSON actual = JSONSerializer.toJSON(reencoded.trim(), cfg);
String exp = expected.toString().replace("\\r\\n", "\\n"); // .replace("&sect;", "§"); String exp = expected.toString().replace("\\r\\n", "\\n"); // .replace("&sect;", "§");
String act = actual.toString().replace("\\r\\n", "\\n"); String act = actual.toString().replace("\\r\\n", "\\n");
@ -67,6 +79,7 @@ public class JsonParserTest {
@Test @Test
public void testParseAndEncodeNewExtensionFormat() { public void testParseAndEncodeNewExtensionFormat() {
//@formatter:off //@formatter:off
String resource = "{\n" + String resource = "{\n" +
" \"resourceType\" : \"Patient\",\n" + " \"resourceType\" : \"Patient\",\n" +
@ -78,7 +91,11 @@ public class JsonParserTest {
" }\n" + " }\n" +
" }]\n" + " }]\n" +
" }],\n" + " }],\n" +
" \"gender\" : \"M\",\n" + " \"modifier\" : { \n" +
" \"http://example.org/fhir/ExtensionDefinition/some-kind-of-modifier\" : [{\n" +
" \"valueBoolean\" : true\n" +
" }]\n" +
" }," +
" \"name\" : [{\n" + " \"name\" : [{\n" +
" \"family\": [\n" + " \"family\": [\n" +
" \"du\",\n" + " \"du\",\n" +
@ -97,14 +114,21 @@ public class JsonParserTest {
" \"given\": [\n" + " \"given\": [\n" +
" \"Bénédicte\"\n" + " \"Bénédicte\"\n" +
" ]\n" + " ]\n" +
" }]" + " }],\n" +
" \"gender\" : \"M\"\n" +
"}"; "}";
//@formatter:on //@formatter:on
ourLog.info(resource); // ourLog.info(resource);
Patient parsed = ourCtx.newJsonParser().parseResource(Patient.class, resource); Patient parsed = ourCtx.newJsonParser().parseResource(Patient.class, resource);
// Modifier extension
assertEquals(1, parsed.getUndeclaredExtensionsByUrl("http://example.org/fhir/ExtensionDefinition/some-kind-of-modifier").size());
assertTrue( parsed.getUndeclaredExtensionsByUrl("http://example.org/fhir/ExtensionDefinition/some-kind-of-modifier").get(0).isModifier());
assertEquals(BooleanDt.class, parsed.getUndeclaredExtensionsByUrl("http://example.org/fhir/ExtensionDefinition/some-kind-of-modifier").get(0).getValueAsPrimitive().getClass());
assertEquals("true", parsed.getUndeclaredExtensionsByUrl("http://example.org/fhir/ExtensionDefinition/some-kind-of-modifier").get(0).getValueAsPrimitive().getValueAsString());
// Gender // Gender
assertEquals("M",parsed.getGender()); assertEquals("M",parsed.getGender());
assertEquals(1, parsed.getUndeclaredExtensionsByUrl("http://acme.org/fhir/ExtensionDefinition/trial-status").size()); assertEquals(1, parsed.getUndeclaredExtensionsByUrl("http://acme.org/fhir/ExtensionDefinition/trial-status").size());
@ -131,6 +155,23 @@ public class JsonParserTest {
assertEquals(CodeDt.class, parsed.getNameFirstRep().getFamily().get(0).getUndeclaredExtensionsByUrl("http://hl7.org/fhir/ExtensionDefinition/iso21090-EN-qualifier").get(0).getValueAsPrimitive().getClass()); assertEquals(CodeDt.class, parsed.getNameFirstRep().getFamily().get(0).getUndeclaredExtensionsByUrl("http://hl7.org/fhir/ExtensionDefinition/iso21090-EN-qualifier").get(0).getValueAsPrimitive().getClass());
assertEquals("VV", parsed.getNameFirstRep().getFamily().get(0).getUndeclaredExtensionsByUrl("http://hl7.org/fhir/ExtensionDefinition/iso21090-EN-qualifier").get(0).getValueAsPrimitive().getValueAsString()); assertEquals("VV", parsed.getNameFirstRep().getFamily().get(0).getUndeclaredExtensionsByUrl("http://hl7.org/fhir/ExtensionDefinition/iso21090-EN-qualifier").get(0).getValueAsPrimitive().getValueAsString());
/*
* Now re-encode
*/
String encoded = ourCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(parsed);
ourLog.info(encoded);
JSON expected = JSONSerializer.toJSON(resource.trim());
JSON actual = JSONSerializer.toJSON(encoded.trim());
String exp = expected.toString().replace("\\r\\n", "\\n"); // .replace("&sect;", "§");
String act = actual.toString().replace("\\r\\n", "\\n");
ourLog.info("Expected: {}", exp);
ourLog.info("Actual : {}", act);
assertEquals(exp, act);
} }

View File

@ -0,0 +1,27 @@
<configuration>
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} [%file:%line] - %msg%n
</pattern>
</encoder>
</appender>
<logger name="org.eclipse" additivity="false" level="info">
<appender-ref ref="STDOUT" />
</logger>
<logger name="org.apache" additivity="false" level="info">
<appender-ref ref="STDOUT" />
</logger>
<!--
<logger name="ca.uhn.fhir.rest.client" additivity="false" level="trace">
<appender-ref ref="STDOUT" />
</logger>
-->
<root level="debug">
<appender-ref ref="STDOUT" />
</root>
</configuration>