Almost have unit tests passing
This commit is contained in:
parent
ebd0f222f4
commit
59ba1c9f7b
|
@ -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());
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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"));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
myUnitTestDB/
|
myUnitTestDB/
|
||||||
target/
|
target/
|
||||||
/bin
|
/bin
|
||||||
|
/target/
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -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("§", "§");
|
String exp = expected.toString().replace("\\r\\n", "\\n"); // .replace("§", "§");
|
||||||
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("§", "§");
|
||||||
|
String act = actual.toString().replace("\\r\\n", "\\n");
|
||||||
|
|
||||||
|
ourLog.info("Expected: {}", exp);
|
||||||
|
ourLog.info("Actual : {}", act);
|
||||||
|
|
||||||
|
assertEquals(exp, act);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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>
|
Loading…
Reference in New Issue