Fix #143 and fix #146 - Issues with resource references for non contained resources when parsing a DSTU2 bundle, and issues encoding contained resources when encoding JSON

This commit is contained in:
jamesagnew 2015-04-03 15:42:02 -04:00
parent 18d45e7cc8
commit 461fdb50ce
12 changed files with 296 additions and 75 deletions

View File

@ -158,7 +158,7 @@ public abstract class BaseParser implements IParser {
}
public void containResourcesForEncoding(IBaseResource theResource) {
protected void containResourcesForEncoding(IBaseResource theResource) {
ContainedResources contained = new ContainedResources();
containResourcesForEncoding(contained, theResource, theResource);
myContainedResources = contained;

View File

@ -457,7 +457,7 @@ public class JsonParser extends BaseParser implements IParser {
case RESOURCE:
IBaseResource resource = (IBaseResource) theNextValue;
RuntimeResourceDefinition def = myContext.getResourceDefinition(resource);
encodeResourceToJsonStreamWriter(def, resource, theWriter, theChildName, true);
encodeResourceToJsonStreamWriter(def, resource, theWriter, theChildName, false);
break;
case UNDECL_EXT:
default:
@ -632,12 +632,12 @@ public class JsonParser extends BaseParser implements IParser {
}
private void encodeResourceToJsonStreamWriter(RuntimeResourceDefinition theResDef, IBaseResource theResource, JsonGenerator theEventWriter, String theObjectNameOrNull,
boolean theIsSubElementWithinResource) throws IOException {
boolean theContainedResource) throws IOException {
String resourceId = null;
if (theResource instanceof IResource) {
IResource res = (IResource) theResource;
if (StringUtils.isNotBlank(res.getId().getIdPart())) {
if (theIsSubElementWithinResource) {
if (theContainedResource) {
resourceId = res.getId().getIdPart();
} else if (myContext.getVersion().getVersion().isNewerThan(FhirVersionEnum.DSTU1)) {
resourceId = res.getId().getIdPart();
@ -645,17 +645,17 @@ public class JsonParser extends BaseParser implements IParser {
}
} else if (theResource instanceof IAnyResource) {
IAnyResource res = (IAnyResource) theResource;
if (theIsSubElementWithinResource && StringUtils.isNotBlank(res.getId())) {
if (theContainedResource && StringUtils.isNotBlank(res.getId())) {
resourceId = res.getId();
}
}
encodeResourceToJsonStreamWriter(theResDef, theResource, theEventWriter, theObjectNameOrNull, theIsSubElementWithinResource, resourceId);
encodeResourceToJsonStreamWriter(theResDef, theResource, theEventWriter, theObjectNameOrNull, theContainedResource, resourceId);
}
private void encodeResourceToJsonStreamWriter(RuntimeResourceDefinition theResDef, IBaseResource theResource, JsonGenerator theEventWriter, String theObjectNameOrNull,
boolean theIsSubElementWithinResource, String theResourceId) throws IOException {
if (!theIsSubElementWithinResource) {
boolean theContainedResource, String theResourceId) throws IOException {
if (!theContainedResource) {
super.containResourcesForEncoding(theResource);
}
@ -704,7 +704,7 @@ public class JsonParser extends BaseParser implements IParser {
for (BaseCodingDt securityLabel : securityLabels) {
theEventWriter.writeStartObject();
BaseRuntimeElementCompositeDefinition<?> def = (BaseRuntimeElementCompositeDefinition<?>) myContext.getElementDefinition(securityLabel.getClass());
encodeCompositeElementChildrenToStreamWriter(resDef, resource, securityLabel, theEventWriter, def.getChildren(), theIsSubElementWithinResource);
encodeCompositeElementChildrenToStreamWriter(resDef, resource, securityLabel, theEventWriter, def.getChildren(), theContainedResource);
theEventWriter.writeEnd();
}
theEventWriter.writeEnd();
@ -731,7 +731,7 @@ public class JsonParser extends BaseParser implements IParser {
theEventWriter.write("contentType", bin.getContentType());
theEventWriter.write("content", bin.getContentAsBase64());
} else {
encodeCompositeElementToStreamWriter(theResDef, theResource, theResource, theEventWriter, resDef, theIsSubElementWithinResource);
encodeCompositeElementToStreamWriter(theResDef, theResource, theResource, theEventWriter, resDef, theContainedResource);
}
theEventWriter.writeEnd();

View File

@ -30,8 +30,6 @@ import java.util.Map;
import javax.xml.stream.events.StartElement;
import javax.xml.stream.events.XMLEvent;
import ca.uhn.fhir.model.base.composite.BaseCodingDt;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.Validate;
import org.hl7.fhir.instance.model.IBase;
@ -39,8 +37,6 @@ import org.hl7.fhir.instance.model.IBaseResource;
import org.hl7.fhir.instance.model.ICompositeType;
import org.hl7.fhir.instance.model.IPrimitiveType;
import org.hl7.fhir.instance.model.api.IBaseBinary;
import org.hl7.fhir.instance.model.api.IAnyResource;
import org.hl7.fhir.instance.model.api.IBaseDatatype;
import org.hl7.fhir.instance.model.api.IBaseElement;
import org.hl7.fhir.instance.model.api.IBaseExtension;
import org.hl7.fhir.instance.model.api.IBaseHasExtensions;
@ -65,7 +61,6 @@ import ca.uhn.fhir.model.api.BundleEntry;
import ca.uhn.fhir.model.api.ExtensionDt;
import ca.uhn.fhir.model.api.ICompositeDatatype;
import ca.uhn.fhir.model.api.IElement;
import ca.uhn.fhir.model.api.IExtension;
import ca.uhn.fhir.model.api.IFhirVersion;
import ca.uhn.fhir.model.api.IIdentifiableElement;
import ca.uhn.fhir.model.api.IPrimitiveDatatype;
@ -74,6 +69,7 @@ import ca.uhn.fhir.model.api.ISupportsUndeclaredExtensions;
import ca.uhn.fhir.model.api.ResourceMetadataKeyEnum;
import ca.uhn.fhir.model.api.Tag;
import ca.uhn.fhir.model.api.TagList;
import ca.uhn.fhir.model.base.composite.BaseCodingDt;
import ca.uhn.fhir.model.base.composite.BaseResourceReferenceDt;
import ca.uhn.fhir.model.base.resource.ResourceMetadataMap;
import ca.uhn.fhir.model.primitive.IdDt;
@ -81,6 +77,7 @@ import ca.uhn.fhir.model.primitive.InstantDt;
import ca.uhn.fhir.model.primitive.StringDt;
import ca.uhn.fhir.model.primitive.XhtmlDt;
import ca.uhn.fhir.rest.server.Constants;
import ca.uhn.fhir.util.FhirTerser;
import ca.uhn.fhir.util.IModelVisitor;
class ParserState<T> {
@ -1465,6 +1462,10 @@ class ParserState<T> {
private class ElementCompositeState extends BaseState {
private BaseRuntimeElementCompositeDefinition<?> myDefinition;
public BaseRuntimeElementCompositeDefinition<?> getDefinition() {
return myDefinition;
}
private IBase myInstance;
public ElementCompositeState(PreResourceState thePreResourceState, BaseRuntimeElementCompositeDefinition<?> theDef, IBase theInstance) {
@ -1570,8 +1571,13 @@ class ParserState<T> {
return;
}
case RESOURCE: {
if (myInstance instanceof IResource) {
ParserState<T>.PreResourceStateHapi state = new PreResourceStateHapi(myInstance, child.getMutator(), null);
push(state);
} else {
ParserState<T>.PreResourceStateHl7Org state = new PreResourceStateHl7Org(myInstance, child.getMutator(), null);
push(state);
}
return;
}
case UNDECL_EXT:
@ -1816,12 +1822,20 @@ class ParserState<T> {
private class PreResourceStateHapi extends PreResourceState {
private BundleEntry myEntry;
private Object myTarget;
private IMutator myMutator;
public PreResourceStateHapi(BundleEntry theEntry, Class<? extends IBaseResource> theResourceType) {
super(theResourceType);
myEntry = theEntry;
}
public PreResourceStateHapi(Object theTarget, IMutator theMutator, Class<? extends IBaseResource> theResourceType) {
super(theResourceType);
myTarget = theTarget;
myMutator = theMutator;
}
public PreResourceStateHapi(Class<? extends IBaseResource> theResourceType) {
super(theResourceType);
}
@ -1833,7 +1847,7 @@ class ParserState<T> {
if (myEntry == null) {
myObject = (T) getCurrentElement();
}
IResource nextResource = (IResource) getCurrentElement();
String version = ResourceMetadataKeyEnum.VERSION.get(nextResource);
String resourceName = myContext.getResourceDefinition(nextResource).getName();
@ -1846,15 +1860,20 @@ class ParserState<T> {
// }
}
}
@Override
public void enteringNewElement(String theNamespaceURI, String theLocalPart) throws DataFormatException {
super.enteringNewElement(theNamespaceURI, theLocalPart);
if (myEntry != null) {
myEntry.setResource((IResource) getCurrentElement());
}
if (myMutator != null) {
myMutator.addValue(myTarget, getCurrentElement());
}
}
}
@ -1976,7 +1995,10 @@ class ParserState<T> {
@Override
public void wereBack() {
myContext.newTerser().visit(myInstance, new IModelVisitor() {
final boolean bundle = "Bundle".equals(myContext.getResourceDefinition(myInstance).getName());
FhirTerser terser = myContext.newTerser();
terser.visit(myInstance, new IModelVisitor() {
@Override
public void acceptElement(IBase theElement, BaseRuntimeChildDefinition theChildDefinition, BaseRuntimeElementDefinition<?> theDefinition) {
@ -2002,6 +2024,35 @@ class ParserState<T> {
}
});
if (bundle) {
/*
* Stitch together resource references
*/
Map<IdDt, IResource> idToResource = new HashMap<IdDt, IResource>();
FhirTerser t = myContext.newTerser();
List<IResource> resources = t.getAllPopulatedChildElementsOfType(myInstance, IResource.class);
for (IResource next : resources) {
IdDt id = next.getId();
if (id != null && id.isEmpty() == false) {
String resName = myContext.getResourceDefinition(next).getName();
idToResource.put(id.withResourceType(resName).toUnqualifiedVersionless(), next);
}
}
for (IResource next : resources) {
List<BaseResourceReferenceDt> refs = myContext.newTerser().getAllPopulatedChildElementsOfType(next, BaseResourceReferenceDt.class);
for (BaseResourceReferenceDt nextRef : refs) {
if (nextRef.isEmpty() == false && nextRef.getReference() != null) {
IResource target = idToResource.get(nextRef.getReference().toUnqualifiedVersionless());
if (target != null) {
nextRef.setResource(target);
}
}
}
}
}
}
}
@ -2264,7 +2315,6 @@ class ParserState<T> {
super.enteringNewElement(theNamespace, theChildName);
}
}
}
private class ResourceStateHl7Org extends ElementCompositeState {

View File

@ -9,9 +9,9 @@ package ca.uhn.fhir.rest.server;
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*
* http://www.apache.org/licenses/LICENSE-2.0
*
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

View File

@ -220,7 +220,7 @@ public class FhirTerser {
}
private <T extends IElement> void visit(IBase theElement, BaseRuntimeChildDefinition theChildDefinition, BaseRuntimeElementDefinition<?> theDefinition, IModelVisitor theCallback) {
private void visit(IBase theElement, BaseRuntimeChildDefinition theChildDefinition, BaseRuntimeElementDefinition<?> theDefinition, IModelVisitor theCallback) {
theCallback.acceptElement(theElement, theChildDefinition, theDefinition);
addUndeclaredExtensions(theElement, theDefinition, theChildDefinition, theCallback);
@ -248,12 +248,7 @@ public class FhirTerser {
break;
case RESOURCE:
case RESOURCE_BLOCK:
case COMPOSITE_DATATYPE: {
if (theChildDefinition instanceof RuntimeChildDirectResource) {
// Don't descend into embedded resources
return;
}
case COMPOSITE_DATATYPE: {
BaseRuntimeElementCompositeDefinition<?> childDef = (BaseRuntimeElementCompositeDefinition<?>) theDefinition;
for (BaseRuntimeChildDefinition nextChild : childDef.getChildrenAndExtension()) {
List<? extends IBase> values = nextChild.getAccessor().getValues(theElement);
@ -286,7 +281,13 @@ public class FhirTerser {
}
throw new DataFormatException(b.toString());
}
visit(nextValue, nextChild, childElementDef, theCallback);
if (nextChild instanceof RuntimeChildDirectResource) {
// Don't descend into embedded resources
theCallback.acceptElement(nextValue, nextChild, childElementDef);
} else {
visit(nextValue, nextChild, childElementDef, theCallback);
}
}
}
}

View File

@ -1,7 +1,7 @@
package ca.uhn.fhir.rest.server;
import static org.hamcrest.Matchers.containsString;
import static org.junit.Assert.*;
import static org.mockito.Matchers.*;
import static org.mockito.Mockito.*;
import java.util.ArrayList;
@ -18,6 +18,7 @@ import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.servlet.ServletHandler;
import org.eclipse.jetty.servlet.ServletHolder;
import org.hamcrest.Matchers;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
@ -63,8 +64,8 @@ public class PagingTest {
assertEquals(200, status.getStatusLine().getStatusCode());
Bundle bundle = ourContext.newXmlParser().parseBundle(responseContent);
assertEquals(5, bundle.getEntries().size());
assertEquals("0", bundle.getEntries().get(0).getId().getIdPart());
assertEquals("4", bundle.getEntries().get(4).getId().getIdPart());
assertEquals("0", bundle.getEntries().get(0).getResource().getId().getIdPart());
assertEquals("4", bundle.getEntries().get(4).getResource().getId().getIdPart());
assertEquals(base + '?' + Constants.PARAM_PAGINGACTION + "=ABCD&" + Constants.PARAM_PAGINGOFFSET + "=5&" + Constants.PARAM_COUNT + "=5&_format=xml&_pretty=true", bundle.getLinkNext()
.getValue());
assertNull(bundle.getLinkPrevious().getValue());
@ -79,8 +80,8 @@ public class PagingTest {
assertEquals(200, status.getStatusLine().getStatusCode());
Bundle bundle = ourContext.newJsonParser().parseBundle(responseContent);
assertEquals(5, bundle.getEntries().size());
assertEquals("5", bundle.getEntries().get(0).getId().getIdPart());
assertEquals("9", bundle.getEntries().get(4).getId().getIdPart());
assertEquals("5", bundle.getEntries().get(0).getResource().getId().getIdPart());
assertEquals("9", bundle.getEntries().get(4).getResource().getId().getIdPart());
assertNull(bundle.getLinkNext().getValue());
assertEquals(base + '?' + Constants.PARAM_PAGINGACTION + "=ABCD&" + Constants.PARAM_PAGINGOFFSET + "=0&" + Constants.PARAM_COUNT + "=5&_format=json&_pretty=true", bundle.getLinkPrevious()
.getValue());
@ -104,8 +105,8 @@ public class PagingTest {
assertEquals(200, status.getStatusLine().getStatusCode());
Bundle bundle = ourContext.newXmlParser().parseBundle(responseContent);
assertEquals(2, bundle.getEntries().size());
assertEquals("8", bundle.getEntries().get(0).getId().getIdPart());
assertEquals("9", bundle.getEntries().get(1).getId().getIdPart());
assertEquals("8", bundle.getEntries().get(0).getResource().getId().getIdPart());
assertEquals("9", bundle.getEntries().get(1).getResource().getId().getIdPart());
assertNull(bundle.getLinkNext().getValue());
assertEquals(base + '?' + Constants.PARAM_PAGINGACTION + "=ABCD&" + Constants.PARAM_PAGINGOFFSET + "=3&" + Constants.PARAM_COUNT + "=5&_format=xml&_pretty=true", bundle.getLinkPrevious()
.getValue());
@ -131,8 +132,8 @@ public class PagingTest {
assertEquals(200, status.getStatusLine().getStatusCode());
Bundle bundle = ourContext.newXmlParser().parseBundle(responseContent);
assertEquals(2, bundle.getEntries().size());
assertEquals("0", bundle.getEntries().get(0).getId().getIdPart());
assertEquals("1", bundle.getEntries().get(1).getId().getIdPart());
assertEquals("0", bundle.getEntries().get(0).getResource().getId().getIdPart());
assertEquals("1", bundle.getEntries().get(1).getResource().getId().getIdPart());
assertEquals(base + '?' + Constants.PARAM_PAGINGACTION + "=ABCD&" + Constants.PARAM_PAGINGOFFSET + "=2&" + Constants.PARAM_COUNT + "=2&_format=xml", bundle.getLinkNext().getValue());
assertNull(bundle.getLinkPrevious().getValue());
link = bundle.getLinkNext().getValue();
@ -146,8 +147,8 @@ public class PagingTest {
assertEquals(200, status.getStatusLine().getStatusCode());
Bundle bundle = ourContext.newXmlParser().parseBundle(responseContent);
assertEquals(2, bundle.getEntries().size());
assertEquals("2", bundle.getEntries().get(0).getId().getIdPart());
assertEquals("3", bundle.getEntries().get(1).getId().getIdPart());
assertEquals("2", bundle.getEntries().get(0).getResource().getId().getIdPart());
assertEquals("3", bundle.getEntries().get(1).getResource().getId().getIdPart());
assertEquals(base + '?' + Constants.PARAM_PAGINGACTION + "=ABCD&" + Constants.PARAM_PAGINGOFFSET + "=4&" + Constants.PARAM_COUNT + "=2&_format=xml", bundle.getLinkNext().getValue());
assertEquals(base + '/' + '?' + Constants.PARAM_PAGINGACTION + "=ABCD&" + Constants.PARAM_PAGINGOFFSET + "=2&" + Constants.PARAM_COUNT + "=2&_format=xml", bundle.getLinkSelf().getValue());
assertEquals(base + '?' + Constants.PARAM_PAGINGACTION + "=ABCD&" + Constants.PARAM_PAGINGOFFSET + "=0&" + Constants.PARAM_COUNT + "=2&_format=xml", bundle.getLinkPrevious().getValue());
@ -175,9 +176,11 @@ public class PagingTest {
assertEquals(200, status.getStatusLine().getStatusCode());
Bundle bundle = ourContext.newXmlParser().parseBundle(responseContent);
assertEquals(2, bundle.getEntries().size());
assertEquals("0", bundle.getEntries().get(0).getId().getIdPart());
assertEquals("1", bundle.getEntries().get(1).getId().getIdPart());
assertEquals(base + '?' + Constants.PARAM_PAGINGACTION + "=ABCD&" + Constants.PARAM_PAGINGOFFSET + "=2&" + Constants.PARAM_COUNT + "=2&_format=xml&_include=Patient.managingOrganization&_include=foo", bundle.getLinkNext().getValue());
assertEquals("0", bundle.getEntries().get(0).getResource().getId().getIdPart());
assertEquals("1", bundle.getEntries().get(1).getResource().getId().getIdPart());
assertThat(bundle.getLinkNext().getValue(), Matchers.startsWith(base + '?' + Constants.PARAM_PAGINGACTION + "=ABCD&" + Constants.PARAM_PAGINGOFFSET + "=2&" + Constants.PARAM_COUNT + "=2&_format=xml"));
assertThat(bundle.getLinkNext().getValue(), containsString("&_include=foo"));
assertThat(bundle.getLinkNext().getValue(), containsString("&_include=Patient.managingOrganization"));
assertNull(bundle.getLinkPrevious().getValue());
link = bundle.getLinkNext().getValue();
}
@ -190,11 +193,19 @@ public class PagingTest {
assertEquals(200, status.getStatusLine().getStatusCode());
Bundle bundle = ourContext.newXmlParser().parseBundle(responseContent);
assertEquals(2, bundle.getEntries().size());
assertEquals("2", bundle.getEntries().get(0).getId().getIdPart());
assertEquals("3", bundle.getEntries().get(1).getId().getIdPart());
assertEquals(base + '?' + Constants.PARAM_PAGINGACTION + "=ABCD&" + Constants.PARAM_PAGINGOFFSET + "=4&" + Constants.PARAM_COUNT + "=2&_format=xml&_include=Patient.managingOrganization&_include=foo", bundle.getLinkNext().getValue());
assertEquals(base + '/' + '?' + Constants.PARAM_PAGINGACTION + "=ABCD&" + Constants.PARAM_PAGINGOFFSET + "=2&" + Constants.PARAM_COUNT + "=2&_format=xml&_include=Patient.managingOrganization&_include=foo", bundle.getLinkSelf().getValue());
assertEquals(base + '?' + Constants.PARAM_PAGINGACTION + "=ABCD&" + Constants.PARAM_PAGINGOFFSET + "=0&" + Constants.PARAM_COUNT + "=2&_format=xml&_include=Patient.managingOrganization&_include=foo", bundle.getLinkPrevious().getValue());
assertEquals("2", bundle.getEntries().get(0).getResource().getId().getIdPart());
assertEquals("3", bundle.getEntries().get(1).getResource().getId().getIdPart());
assertThat(bundle.getLinkNext().getValue(), Matchers.startsWith(base + '?' + Constants.PARAM_PAGINGACTION + "=ABCD&" + Constants.PARAM_PAGINGOFFSET + "=4&" + Constants.PARAM_COUNT + "=2&_format=xml"));
assertThat(bundle.getLinkNext().getValue(), containsString("&_include=foo"));
assertThat(bundle.getLinkNext().getValue(), containsString("&_include=Patient.managingOrganization"));
assertThat(bundle.getLinkSelf().getValue(), Matchers.startsWith(base + '/' + '?' + Constants.PARAM_PAGINGACTION + "=ABCD&" + Constants.PARAM_PAGINGOFFSET + "=2&" + Constants.PARAM_COUNT + "=2&_format=xml"));
assertThat(bundle.getLinkSelf().getValue(), containsString("&_include=foo"));
assertThat(bundle.getLinkSelf().getValue(), containsString("&_include=Patient.managingOrganization"));
assertThat(bundle.getLinkPrevious().getValue(), Matchers.startsWith(base + '?' + Constants.PARAM_PAGINGACTION + "=ABCD&" + Constants.PARAM_PAGINGOFFSET + "=0&" + Constants.PARAM_COUNT + "=2&_format=xml"));
assertThat(bundle.getLinkPrevious().getValue(), containsString("&_include=foo"));
assertThat(bundle.getLinkPrevious().getValue(), containsString("&_include=Patient.managingOrganization"));
}
}
@ -216,8 +227,8 @@ public class PagingTest {
assertEquals(200, status.getStatusLine().getStatusCode());
Bundle bundle = ourContext.newXmlParser().parseBundle(responseContent);
assertEquals(2, bundle.getEntries().size());
assertEquals("0", bundle.getEntries().get(0).getId().getIdPart());
assertEquals("1", bundle.getEntries().get(1).getId().getIdPart());
assertEquals("0", bundle.getEntries().get(0).getResource().getId().getIdPart());
assertEquals("1", bundle.getEntries().get(1).getResource().getId().getIdPart());
assertEquals(base + '?' + Constants.PARAM_PAGINGACTION + "=ABCD&" + Constants.PARAM_PAGINGOFFSET + "=2&" + Constants.PARAM_COUNT + "=2", bundle.getLinkNext().getValue());
assertNull(bundle.getLinkPrevious().getValue());
link = bundle.getLinkNext().getValue();
@ -231,8 +242,8 @@ public class PagingTest {
assertEquals(200, status.getStatusLine().getStatusCode());
Bundle bundle = ourContext.newXmlParser().parseBundle(responseContent);
assertEquals(2, bundle.getEntries().size());
assertEquals("2", bundle.getEntries().get(0).getId().getIdPart());
assertEquals("3", bundle.getEntries().get(1).getId().getIdPart());
assertEquals("2", bundle.getEntries().get(0).getResource().getId().getIdPart());
assertEquals("3", bundle.getEntries().get(1).getResource().getId().getIdPart());
assertEquals(base + '?' + Constants.PARAM_PAGINGACTION + "=ABCD&" + Constants.PARAM_PAGINGOFFSET + "=4&" + Constants.PARAM_COUNT + "=2", bundle.getLinkNext().getValue());
assertEquals(base + '/' + '?' + Constants.PARAM_PAGINGACTION + "=ABCD&" + Constants.PARAM_PAGINGOFFSET + "=2&" + Constants.PARAM_COUNT + "=2", bundle.getLinkSelf().getValue());
assertEquals(base + '?' + Constants.PARAM_PAGINGACTION + "=ABCD&" + Constants.PARAM_PAGINGOFFSET + "=0&" + Constants.PARAM_COUNT + "=2", bundle.getLinkPrevious().getValue());

View File

@ -98,7 +98,7 @@ public class ServerConformanceProvider implements IServerConformanceProvider<Con
retVal.setPublisher(myPublisher);
retVal.setDate(DateTimeDt.withCurrentTime());
retVal.setFhirVersion("0.4.0"); // TODO: pull from model
retVal.setFhirVersion("0.5.0"); // TODO: pull from model
retVal.setAcceptUnknown(false); // TODO: make this configurable - this is a fairly big effort since the parser
// needs to be modified to actually allow it

View File

@ -12,7 +12,6 @@ import net.sf.json.JSONSerializer;
import net.sf.json.JsonConfig;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.hamcrest.Matchers;
import org.junit.Assert;
import org.junit.Test;
@ -468,6 +467,34 @@ public class JsonParserDstu2Test {
assertNull(ResourceMetadataKeyEnum.PROFILES.get(patient));
}
/**
* Test for #146
*/
@Test
public void testParseAndEncodeBundleFromXmlToJson() throws Exception {
String content = IOUtils.toString(JsonParserDstu2Test.class.getResourceAsStream("/bundle-example2.xml"));
ca.uhn.fhir.model.dstu2.resource.Bundle parsed = ourCtx.newXmlParser().parseResource(ca.uhn.fhir.model.dstu2.resource.Bundle.class, content);
MedicationPrescription p = (MedicationPrescription) parsed.getEntry().get(0).getResource();
assertEquals("#med", p.getMedication().getReference().getValue());
Medication m = (Medication) p.getMedication().getResource();
assertNotNull(m);
assertEquals("#med", m.getId().getValue());
assertEquals(1, p.getContained().getContainedResources().size());
assertSame(m, p.getContained().getContainedResources().get(0));
String reencoded = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(parsed);
ourLog.info(reencoded);
assertThat(reencoded, containsString("contained"));
reencoded = ourCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(parsed);
ourLog.info(reencoded);
assertThat(reencoded, containsString("contained"));
}
@Test
public void testParseAndEncodeBundle() throws Exception {
String content = IOUtils.toString(JsonParserDstu2Test.class.getResourceAsStream("/bundle-example.json"));
@ -514,28 +541,26 @@ public class JsonParserDstu2Test {
@Test
public void testParseAndEncodeBundleOldStyle() throws Exception {
String content = IOUtils.toString(JsonParserDstu2Test.class.getResourceAsStream("/bundle-transaction.json"));
String content = IOUtils.toString(JsonParserDstu2Test.class.getResourceAsStream("/bundle-example.json"));
Bundle parsed = ourCtx.newJsonParser().parseBundle(content);
// assertEquals("http://example.com/base/Bundle/example/_history/1", parsed.getId().getValue());
// assertEquals("1", parsed.getResourceMetadata().get(ResourceMetadataKeyEnum.VERSION));
// assertEquals("1", parsed.getId().getVersionIdPart());
// assertEquals(new InstantDt("2014-08-18T01:43:30Z"),
// parsed.getResourceMetadata().get(ResourceMetadataKeyEnum.UPDATED));
// assertEquals("searchset", parsed.getType().getValue());
// assertEquals(3, parsed.getTotalResults().getValue().intValue());
// assertEquals("http://example.com/base", parsed.getLinkBase().getValue());
// assertEquals("https://example.com/base/MedicationPrescription?patient=347&searchId=ff15fd40-ff71-4b48-b366-09c706bed9d0&page=2",
// parsed.getLinkNext().getValue());
// assertEquals("https://example.com/base/MedicationPrescription?patient=347&_include=MedicationPrescription.medication",
// parsed.getLinkSelf().getValue());
//
// assertEquals(2, parsed.getEntries().size());
//
// MedicationPrescription p = (MedicationPrescription) parsed.getEntries().get(0).getResource();
// assertEquals("Patient/347", p.getPatient().getReference().getValue());
// assertEquals("2014-08-16T05:31:17Z", ResourceMetadataKeyEnum.UPDATED.get(p).getValueAsString());
// assertEquals("http://example.com/base/MedicationPrescription/3123/_history/1", p.getId().getValue());
assertEquals(new InstantDt("2014-08-18T01:43:30Z"), parsed.getResourceMetadata().get(ResourceMetadataKeyEnum.UPDATED));
assertEquals("searchset", parsed.getType().getValue());
assertEquals(3, parsed.getTotalResults().getValue().intValue());
assertEquals(2, parsed.getEntries().size());
MedicationPrescription p = (MedicationPrescription) parsed.getEntries().get(0).getResource();
assertEquals("Patient/347", p.getPatient().getReference().getValue());
assertEquals("2014-08-16T05:31:17Z", ResourceMetadataKeyEnum.UPDATED.get(p).getValueAsString());
assertEquals("http://example.com/base/MedicationPrescription/3123/_history/1", p.getId().getValue());
Medication m = (Medication) parsed.getEntries().get(1).getResource();
assertEquals("http://example.com/base/Medication/example", m.getId().getValue());
assertEquals("Medication/example", p.getMedication().getReference().getValue());
assertSame(p.getMedication().getResource(), m);
String reencoded = ourCtx.newJsonParser().setPrettyPrint(true).encodeBundleToString(parsed);
ourLog.info(reencoded);
@ -579,6 +604,11 @@ public class JsonParserDstu2Test {
assertEquals("2014-08-16T05:31:17Z", ResourceMetadataKeyEnum.UPDATED.get(p).getValueAsString());
assertEquals("http://example.com/base/MedicationPrescription/3123/_history/1", p.getId().getValue());
Medication m = (Medication) parsed.getEntry().get(1).getResource();
assertEquals("http://example.com/base/Medication/example", m.getId().getValue());
assertEquals("Medication/example", p.getMedication().getReference().getValue());
assertSame(p.getMedication().getResource(), m);
String reencoded = ourCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(parsed);
ourLog.info(reencoded);

View File

@ -405,6 +405,10 @@ public class XmlParserDstu2Test {
assertEquals("2014-08-16T05:31:17Z", ResourceMetadataKeyEnum.UPDATED.get(p).getValueAsString());
assertEquals("http://example.com/base/MedicationPrescription/3123/_history/1", p.getId().getValue());
Medication m = (Medication) parsed.getEntries().get(1).getResource();
assertEquals("http://example.com/base/Medication/example", m.getId().getValue());
assertSame(p.getMedication().getResource(), m);
String reencoded = ourCtx.newXmlParser().setPrettyPrint(true).encodeBundleToString(parsed);
ourLog.info(reencoded);
@ -437,6 +441,10 @@ public class XmlParserDstu2Test {
assertEquals("http://example.com/base/MedicationPrescription/3123/_history/1", p.getId().getValue());
// assertEquals("3123", p.getId().getValue());
Medication m = (Medication) parsed.getEntry().get(1).getResource();
assertEquals("http://example.com/base/Medication/example", m.getId().getValue());
assertSame(p.getMedication().getResource(), m);
String reencoded = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(parsed);
ourLog.info(reencoded);

View File

@ -52,7 +52,7 @@ public class ClientServerValidationTestDstu2 {
}
@Test
public void testServerReturnsAppropriateVersionForDstu2() throws Exception {
public void testServerReturnsAppropriateVersionForDstu2_040() throws Exception {
Conformance conf = new Conformance();
conf.setFhirVersion("0.4.0");
final String confResource = myCtx.newXmlParser().encodeResourceToString(conf);
@ -88,6 +88,43 @@ public class ClientServerValidationTestDstu2 {
verify(myHttpClient, times(4)).execute(Matchers.any(HttpUriRequest.class));
}
@Test
public void testServerReturnsAppropriateVersionForDstu2_050() throws Exception {
Conformance conf = new Conformance();
conf.setFhirVersion("0.5.0");
final String confResource = myCtx.newXmlParser().encodeResourceToString(conf);
ArgumentCaptor<HttpUriRequest> capt = ArgumentCaptor.forClass(HttpUriRequest.class);
when(myHttpResponse.getStatusLine()).thenReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 200, "OK"));
when(myHttpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", Constants.CT_FHIR_XML + "; charset=UTF-8"));
when(myHttpResponse.getEntity().getContent()).thenAnswer(new Answer<InputStream>() {
@Override
public InputStream answer(InvocationOnMock theInvocation) throws Throwable {
if (myFirstResponse) {
myFirstResponse=false;
return new ReaderInputStream(new StringReader(confResource), Charset.forName("UTF-8"));
} else {
return new ReaderInputStream(new StringReader(myCtx.newXmlParser().encodeResourceToString(new Patient())), Charset.forName("UTF-8"));
}
}});
when(myHttpClient.execute(capt.capture())).thenReturn(myHttpResponse);
myCtx.getRestfulClientFactory().setServerValidationModeEnum(ServerValidationModeEnum.ONCE);
IGenericClient client = myCtx.newRestfulGenericClient("http://foo");
// don't load the conformance until the first time the client is actually used
assertTrue(myFirstResponse);
client.read(new UriDt("http://foo/Patient/123"));
assertFalse(myFirstResponse);
myCtx.newRestfulGenericClient("http://foo").read(new UriDt("http://foo/Patient/123"));
myCtx.newRestfulGenericClient("http://foo").read(new UriDt("http://foo/Patient/123"));
// Conformance only loaded once, then 3 reads
verify(myHttpClient, times(4)).execute(Matchers.any(HttpUriRequest.class));
}
@Test
public void testServerReturnsWrongVersionForDstu2() throws Exception {
Conformance conf = new Conformance();

View File

@ -0,0 +1,72 @@
<Bundle xmlns="http://hl7.org/fhir">
<id value="09105af9-528c-47d0-a844-b7964236d6ff"/>
<type value="searchset"/>
<base value="http://fhirtest.uhn.ca/baseDstu2"/>
<total value="1"/>
<link>
<relation value="self"/>
<url value="http://10.160.2.151:28080/hapi-fhir-jpaserver/baseDstu2/MedicationPrescription?patient=13123&amp;_format=xml"/>
</link>
<entry>
<resource>
<MedicationPrescription xmlns="http://hl7.org/fhir">
<id value="20399"/>
<meta>
<versionId value="1"/>
<lastUpdated value="2015-04-02T20:31:44.459-04:00"/>
</meta>
<text>
<status value="generated"/>
<div xmlns="http://www.w3.org/1999/xhtml"> Thyroxine 0.112 MG Oral Tablet [Levoxyl] (rxnorm: 206485) </div>
</text>
<contained>
<Medication xmlns="http://hl7.org/fhir">
<id value="med"/>
<name value="Thyroxine 0.112 MG Oral Tablet [Levoxyl]"/>
<code>
<coding>
<system value="http://www.nlm.nih.gov/research/umls/rxnorm"/>
<code value="206485"/>
<display value="Thyroxine 0.112 MG Oral Tablet [Levoxyl]"/>
</coding>
</code>
</Medication>
</contained>
<status value="active"/>
<patient>
<reference value="Patient/13123"/>
</patient>
<medication>
<reference value="#med"/>
</medication>
<dosageInstruction>
<text value="1 daily"/>
<doseQuantity>
<value value="1"/>
<units value="{tablet}"/>
<system value="http://unitsofmeasure.org"/>
<code value="{tablet}"/>
</doseQuantity>
</dosageInstruction>
<dispense>
<numberOfRepeatsAllowed value="1"/>
<quantity>
<value value="90"/>
<units value="{tablet}"/>
<system value="http://unitsofmeasure.org"/>
<code value="{tablet}"/>
</quantity>
<expectedSupplyDuration>
<value value="90"/>
<units value="days"/>
<system value="http://unitsofmeasure.org"/>
<code value="d"/>
</expectedSupplyDuration>
</dispense>
</MedicationPrescription>
</resource>
<search>
<mode value="match"/>
</search>
</entry>
</Bundle>

View File

@ -102,6 +102,18 @@
server behind an Apache proxy (e.g. for load balancing or other reasons).
Thanks to Bill de Beaubien for contributing!
</action>
<action type="fix" issue="143">
Resource references between separate resources found in a single
bundle did not get populated with the actual resource when parsing a
DSTU2 style bundle. Thanks to Nick Peterson for reporting and figuring
out why none of our unit tests were actually catching the problem!
</action>
<action type="fix" issue="146">
JSON encoder did not encode contained resources when encoding
a DSTU2 style bundle. Thanks to Mohammad Jafari and baopingle
for all of their help in tracking this issue down and developing
useful unit tests to demonstrate it.
</action>
</release>
<release version="0.9" date="2015-Mar-14">
<action type="add">