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(); ContainedResources contained = new ContainedResources();
containResourcesForEncoding(contained, theResource, theResource); containResourcesForEncoding(contained, theResource, theResource);
myContainedResources = contained; myContainedResources = contained;

View File

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

View File

@ -30,8 +30,6 @@ import java.util.Map;
import javax.xml.stream.events.StartElement; import javax.xml.stream.events.StartElement;
import javax.xml.stream.events.XMLEvent; 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.StringUtils;
import org.apache.commons.lang3.Validate; import org.apache.commons.lang3.Validate;
import org.hl7.fhir.instance.model.IBase; 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.ICompositeType;
import org.hl7.fhir.instance.model.IPrimitiveType; import org.hl7.fhir.instance.model.IPrimitiveType;
import org.hl7.fhir.instance.model.api.IBaseBinary; 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.IBaseElement;
import org.hl7.fhir.instance.model.api.IBaseExtension; import org.hl7.fhir.instance.model.api.IBaseExtension;
import org.hl7.fhir.instance.model.api.IBaseHasExtensions; 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.ExtensionDt;
import ca.uhn.fhir.model.api.ICompositeDatatype; import ca.uhn.fhir.model.api.ICompositeDatatype;
import ca.uhn.fhir.model.api.IElement; 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.IFhirVersion;
import ca.uhn.fhir.model.api.IIdentifiableElement; import ca.uhn.fhir.model.api.IIdentifiableElement;
import ca.uhn.fhir.model.api.IPrimitiveDatatype; 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.ResourceMetadataKeyEnum;
import ca.uhn.fhir.model.api.Tag; import ca.uhn.fhir.model.api.Tag;
import ca.uhn.fhir.model.api.TagList; 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.composite.BaseResourceReferenceDt;
import ca.uhn.fhir.model.base.resource.ResourceMetadataMap; import ca.uhn.fhir.model.base.resource.ResourceMetadataMap;
import ca.uhn.fhir.model.primitive.IdDt; 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.StringDt;
import ca.uhn.fhir.model.primitive.XhtmlDt; import ca.uhn.fhir.model.primitive.XhtmlDt;
import ca.uhn.fhir.rest.server.Constants; import ca.uhn.fhir.rest.server.Constants;
import ca.uhn.fhir.util.FhirTerser;
import ca.uhn.fhir.util.IModelVisitor; import ca.uhn.fhir.util.IModelVisitor;
class ParserState<T> { class ParserState<T> {
@ -1465,6 +1462,10 @@ class ParserState<T> {
private class ElementCompositeState extends BaseState { private class ElementCompositeState extends BaseState {
private BaseRuntimeElementCompositeDefinition<?> myDefinition; private BaseRuntimeElementCompositeDefinition<?> myDefinition;
public BaseRuntimeElementCompositeDefinition<?> getDefinition() {
return myDefinition;
}
private IBase myInstance; private IBase myInstance;
public ElementCompositeState(PreResourceState thePreResourceState, BaseRuntimeElementCompositeDefinition<?> theDef, IBase theInstance) { public ElementCompositeState(PreResourceState thePreResourceState, BaseRuntimeElementCompositeDefinition<?> theDef, IBase theInstance) {
@ -1570,8 +1571,13 @@ class ParserState<T> {
return; return;
} }
case RESOURCE: { 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); ParserState<T>.PreResourceStateHl7Org state = new PreResourceStateHl7Org(myInstance, child.getMutator(), null);
push(state); push(state);
}
return; return;
} }
case UNDECL_EXT: case UNDECL_EXT:
@ -1816,12 +1822,20 @@ class ParserState<T> {
private class PreResourceStateHapi extends PreResourceState { private class PreResourceStateHapi extends PreResourceState {
private BundleEntry myEntry; private BundleEntry myEntry;
private Object myTarget;
private IMutator myMutator;
public PreResourceStateHapi(BundleEntry theEntry, Class<? extends IBaseResource> theResourceType) { public PreResourceStateHapi(BundleEntry theEntry, Class<? extends IBaseResource> theResourceType) {
super(theResourceType); super(theResourceType);
myEntry = theEntry; myEntry = theEntry;
} }
public PreResourceStateHapi(Object theTarget, IMutator theMutator, Class<? extends IBaseResource> theResourceType) {
super(theResourceType);
myTarget = theTarget;
myMutator = theMutator;
}
public PreResourceStateHapi(Class<? extends IBaseResource> theResourceType) { public PreResourceStateHapi(Class<? extends IBaseResource> theResourceType) {
super(theResourceType); super(theResourceType);
} }
@ -1833,7 +1847,7 @@ class ParserState<T> {
if (myEntry == null) { if (myEntry == null) {
myObject = (T) getCurrentElement(); myObject = (T) getCurrentElement();
} }
IResource nextResource = (IResource) getCurrentElement(); IResource nextResource = (IResource) getCurrentElement();
String version = ResourceMetadataKeyEnum.VERSION.get(nextResource); String version = ResourceMetadataKeyEnum.VERSION.get(nextResource);
String resourceName = myContext.getResourceDefinition(nextResource).getName(); String resourceName = myContext.getResourceDefinition(nextResource).getName();
@ -1846,15 +1860,20 @@ class ParserState<T> {
// } // }
} }
} }
@Override @Override
public void enteringNewElement(String theNamespaceURI, String theLocalPart) throws DataFormatException { public void enteringNewElement(String theNamespaceURI, String theLocalPart) throws DataFormatException {
super.enteringNewElement(theNamespaceURI, theLocalPart); super.enteringNewElement(theNamespaceURI, theLocalPart);
if (myEntry != null) { if (myEntry != null) {
myEntry.setResource((IResource) getCurrentElement()); myEntry.setResource((IResource) getCurrentElement());
} }
if (myMutator != null) {
myMutator.addValue(myTarget, getCurrentElement());
}
} }
} }
@ -1976,7 +1995,10 @@ class ParserState<T> {
@Override @Override
public void wereBack() { 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 @Override
public void acceptElement(IBase theElement, BaseRuntimeChildDefinition theChildDefinition, BaseRuntimeElementDefinition<?> theDefinition) { 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); super.enteringNewElement(theNamespace, theChildName);
} }
} }
} }
private class ResourceStateHl7Org extends ElementCompositeState { 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"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * 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); theCallback.acceptElement(theElement, theChildDefinition, theDefinition);
addUndeclaredExtensions(theElement, theDefinition, theChildDefinition, theCallback); addUndeclaredExtensions(theElement, theDefinition, theChildDefinition, theCallback);
@ -248,12 +248,7 @@ public class FhirTerser {
break; break;
case RESOURCE: case RESOURCE:
case RESOURCE_BLOCK: case RESOURCE_BLOCK:
case COMPOSITE_DATATYPE: { case COMPOSITE_DATATYPE: {
if (theChildDefinition instanceof RuntimeChildDirectResource) {
// Don't descend into embedded resources
return;
}
BaseRuntimeElementCompositeDefinition<?> childDef = (BaseRuntimeElementCompositeDefinition<?>) theDefinition; BaseRuntimeElementCompositeDefinition<?> childDef = (BaseRuntimeElementCompositeDefinition<?>) theDefinition;
for (BaseRuntimeChildDefinition nextChild : childDef.getChildrenAndExtension()) { for (BaseRuntimeChildDefinition nextChild : childDef.getChildrenAndExtension()) {
List<? extends IBase> values = nextChild.getAccessor().getValues(theElement); List<? extends IBase> values = nextChild.getAccessor().getValues(theElement);
@ -286,7 +281,13 @@ public class FhirTerser {
} }
throw new DataFormatException(b.toString()); 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; package ca.uhn.fhir.rest.server;
import static org.hamcrest.Matchers.containsString;
import static org.junit.Assert.*; import static org.junit.Assert.*;
import static org.mockito.Matchers.*;
import static org.mockito.Mockito.*; import static org.mockito.Mockito.*;
import java.util.ArrayList; 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.server.Server;
import org.eclipse.jetty.servlet.ServletHandler; import org.eclipse.jetty.servlet.ServletHandler;
import org.eclipse.jetty.servlet.ServletHolder; import org.eclipse.jetty.servlet.ServletHolder;
import org.hamcrest.Matchers;
import org.junit.AfterClass; import org.junit.AfterClass;
import org.junit.Before; import org.junit.Before;
import org.junit.BeforeClass; import org.junit.BeforeClass;
@ -63,8 +64,8 @@ public class PagingTest {
assertEquals(200, status.getStatusLine().getStatusCode()); assertEquals(200, status.getStatusLine().getStatusCode());
Bundle bundle = ourContext.newXmlParser().parseBundle(responseContent); Bundle bundle = ourContext.newXmlParser().parseBundle(responseContent);
assertEquals(5, bundle.getEntries().size()); assertEquals(5, bundle.getEntries().size());
assertEquals("0", bundle.getEntries().get(0).getId().getIdPart()); assertEquals("0", bundle.getEntries().get(0).getResource().getId().getIdPart());
assertEquals("4", bundle.getEntries().get(4).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() assertEquals(base + '?' + Constants.PARAM_PAGINGACTION + "=ABCD&" + Constants.PARAM_PAGINGOFFSET + "=5&" + Constants.PARAM_COUNT + "=5&_format=xml&_pretty=true", bundle.getLinkNext()
.getValue()); .getValue());
assertNull(bundle.getLinkPrevious().getValue()); assertNull(bundle.getLinkPrevious().getValue());
@ -79,8 +80,8 @@ public class PagingTest {
assertEquals(200, status.getStatusLine().getStatusCode()); assertEquals(200, status.getStatusLine().getStatusCode());
Bundle bundle = ourContext.newJsonParser().parseBundle(responseContent); Bundle bundle = ourContext.newJsonParser().parseBundle(responseContent);
assertEquals(5, bundle.getEntries().size()); assertEquals(5, bundle.getEntries().size());
assertEquals("5", bundle.getEntries().get(0).getId().getIdPart()); assertEquals("5", bundle.getEntries().get(0).getResource().getId().getIdPart());
assertEquals("9", bundle.getEntries().get(4).getId().getIdPart()); assertEquals("9", bundle.getEntries().get(4).getResource().getId().getIdPart());
assertNull(bundle.getLinkNext().getValue()); assertNull(bundle.getLinkNext().getValue());
assertEquals(base + '?' + Constants.PARAM_PAGINGACTION + "=ABCD&" + Constants.PARAM_PAGINGOFFSET + "=0&" + Constants.PARAM_COUNT + "=5&_format=json&_pretty=true", bundle.getLinkPrevious() assertEquals(base + '?' + Constants.PARAM_PAGINGACTION + "=ABCD&" + Constants.PARAM_PAGINGOFFSET + "=0&" + Constants.PARAM_COUNT + "=5&_format=json&_pretty=true", bundle.getLinkPrevious()
.getValue()); .getValue());
@ -104,8 +105,8 @@ public class PagingTest {
assertEquals(200, status.getStatusLine().getStatusCode()); assertEquals(200, status.getStatusLine().getStatusCode());
Bundle bundle = ourContext.newXmlParser().parseBundle(responseContent); Bundle bundle = ourContext.newXmlParser().parseBundle(responseContent);
assertEquals(2, bundle.getEntries().size()); assertEquals(2, bundle.getEntries().size());
assertEquals("8", bundle.getEntries().get(0).getId().getIdPart()); assertEquals("8", bundle.getEntries().get(0).getResource().getId().getIdPart());
assertEquals("9", bundle.getEntries().get(1).getId().getIdPart()); assertEquals("9", bundle.getEntries().get(1).getResource().getId().getIdPart());
assertNull(bundle.getLinkNext().getValue()); assertNull(bundle.getLinkNext().getValue());
assertEquals(base + '?' + Constants.PARAM_PAGINGACTION + "=ABCD&" + Constants.PARAM_PAGINGOFFSET + "=3&" + Constants.PARAM_COUNT + "=5&_format=xml&_pretty=true", bundle.getLinkPrevious() assertEquals(base + '?' + Constants.PARAM_PAGINGACTION + "=ABCD&" + Constants.PARAM_PAGINGOFFSET + "=3&" + Constants.PARAM_COUNT + "=5&_format=xml&_pretty=true", bundle.getLinkPrevious()
.getValue()); .getValue());
@ -131,8 +132,8 @@ public class PagingTest {
assertEquals(200, status.getStatusLine().getStatusCode()); assertEquals(200, status.getStatusLine().getStatusCode());
Bundle bundle = ourContext.newXmlParser().parseBundle(responseContent); Bundle bundle = ourContext.newXmlParser().parseBundle(responseContent);
assertEquals(2, bundle.getEntries().size()); assertEquals(2, bundle.getEntries().size());
assertEquals("0", bundle.getEntries().get(0).getId().getIdPart()); assertEquals("0", bundle.getEntries().get(0).getResource().getId().getIdPart());
assertEquals("1", bundle.getEntries().get(1).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()); assertEquals(base + '?' + Constants.PARAM_PAGINGACTION + "=ABCD&" + Constants.PARAM_PAGINGOFFSET + "=2&" + Constants.PARAM_COUNT + "=2&_format=xml", bundle.getLinkNext().getValue());
assertNull(bundle.getLinkPrevious().getValue()); assertNull(bundle.getLinkPrevious().getValue());
link = bundle.getLinkNext().getValue(); link = bundle.getLinkNext().getValue();
@ -146,8 +147,8 @@ public class PagingTest {
assertEquals(200, status.getStatusLine().getStatusCode()); assertEquals(200, status.getStatusLine().getStatusCode());
Bundle bundle = ourContext.newXmlParser().parseBundle(responseContent); Bundle bundle = ourContext.newXmlParser().parseBundle(responseContent);
assertEquals(2, bundle.getEntries().size()); assertEquals(2, bundle.getEntries().size());
assertEquals("2", bundle.getEntries().get(0).getId().getIdPart()); assertEquals("2", bundle.getEntries().get(0).getResource().getId().getIdPart());
assertEquals("3", bundle.getEntries().get(1).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 + "=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 + "=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()); 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()); assertEquals(200, status.getStatusLine().getStatusCode());
Bundle bundle = ourContext.newXmlParser().parseBundle(responseContent); Bundle bundle = ourContext.newXmlParser().parseBundle(responseContent);
assertEquals(2, bundle.getEntries().size()); assertEquals(2, bundle.getEntries().size());
assertEquals("0", bundle.getEntries().get(0).getId().getIdPart()); assertEquals("0", bundle.getEntries().get(0).getResource().getId().getIdPart());
assertEquals("1", bundle.getEntries().get(1).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&_include=Patient.managingOrganization&_include=foo", bundle.getLinkNext().getValue()); 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()); assertNull(bundle.getLinkPrevious().getValue());
link = bundle.getLinkNext().getValue(); link = bundle.getLinkNext().getValue();
} }
@ -190,11 +193,19 @@ public class PagingTest {
assertEquals(200, status.getStatusLine().getStatusCode()); assertEquals(200, status.getStatusLine().getStatusCode());
Bundle bundle = ourContext.newXmlParser().parseBundle(responseContent); Bundle bundle = ourContext.newXmlParser().parseBundle(responseContent);
assertEquals(2, bundle.getEntries().size()); assertEquals(2, bundle.getEntries().size());
assertEquals("2", bundle.getEntries().get(0).getId().getIdPart()); assertEquals("2", bundle.getEntries().get(0).getResource().getId().getIdPart());
assertEquals("3", bundle.getEntries().get(1).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&_include=Patient.managingOrganization&_include=foo", bundle.getLinkNext().getValue()); assertThat(bundle.getLinkNext().getValue(), Matchers.startsWith(base + '?' + Constants.PARAM_PAGINGACTION + "=ABCD&" + Constants.PARAM_PAGINGOFFSET + "=4&" + Constants.PARAM_COUNT + "=2&_format=xml"));
assertEquals(base + '/' + '?' + Constants.PARAM_PAGINGACTION + "=ABCD&" + Constants.PARAM_PAGINGOFFSET + "=2&" + Constants.PARAM_COUNT + "=2&_format=xml&_include=Patient.managingOrganization&_include=foo", bundle.getLinkSelf().getValue()); assertThat(bundle.getLinkNext().getValue(), containsString("&_include=foo"));
assertEquals(base + '?' + Constants.PARAM_PAGINGACTION + "=ABCD&" + Constants.PARAM_PAGINGOFFSET + "=0&" + Constants.PARAM_COUNT + "=2&_format=xml&_include=Patient.managingOrganization&_include=foo", bundle.getLinkPrevious().getValue()); 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()); assertEquals(200, status.getStatusLine().getStatusCode());
Bundle bundle = ourContext.newXmlParser().parseBundle(responseContent); Bundle bundle = ourContext.newXmlParser().parseBundle(responseContent);
assertEquals(2, bundle.getEntries().size()); assertEquals(2, bundle.getEntries().size());
assertEquals("0", bundle.getEntries().get(0).getId().getIdPart()); assertEquals("0", bundle.getEntries().get(0).getResource().getId().getIdPart());
assertEquals("1", bundle.getEntries().get(1).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()); assertEquals(base + '?' + Constants.PARAM_PAGINGACTION + "=ABCD&" + Constants.PARAM_PAGINGOFFSET + "=2&" + Constants.PARAM_COUNT + "=2", bundle.getLinkNext().getValue());
assertNull(bundle.getLinkPrevious().getValue()); assertNull(bundle.getLinkPrevious().getValue());
link = bundle.getLinkNext().getValue(); link = bundle.getLinkNext().getValue();
@ -231,8 +242,8 @@ public class PagingTest {
assertEquals(200, status.getStatusLine().getStatusCode()); assertEquals(200, status.getStatusLine().getStatusCode());
Bundle bundle = ourContext.newXmlParser().parseBundle(responseContent); Bundle bundle = ourContext.newXmlParser().parseBundle(responseContent);
assertEquals(2, bundle.getEntries().size()); assertEquals(2, bundle.getEntries().size());
assertEquals("2", bundle.getEntries().get(0).getId().getIdPart()); assertEquals("2", bundle.getEntries().get(0).getResource().getId().getIdPart());
assertEquals("3", bundle.getEntries().get(1).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 + "=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 + "=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()); 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.setPublisher(myPublisher);
retVal.setDate(DateTimeDt.withCurrentTime()); 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 retVal.setAcceptUnknown(false); // TODO: make this configurable - this is a fairly big effort since the parser
// needs to be modified to actually allow it // 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 net.sf.json.JsonConfig;
import org.apache.commons.io.IOUtils; import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.hamcrest.Matchers; import org.hamcrest.Matchers;
import org.junit.Assert; import org.junit.Assert;
import org.junit.Test; import org.junit.Test;
@ -468,6 +467,34 @@ public class JsonParserDstu2Test {
assertNull(ResourceMetadataKeyEnum.PROFILES.get(patient)); 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 @Test
public void testParseAndEncodeBundle() throws Exception { public void testParseAndEncodeBundle() throws Exception {
String content = IOUtils.toString(JsonParserDstu2Test.class.getResourceAsStream("/bundle-example.json")); String content = IOUtils.toString(JsonParserDstu2Test.class.getResourceAsStream("/bundle-example.json"));
@ -514,28 +541,26 @@ public class JsonParserDstu2Test {
@Test @Test
public void testParseAndEncodeBundleOldStyle() throws Exception { 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); 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(new InstantDt("2014-08-18T01:43:30Z"), parsed.getResourceMetadata().get(ResourceMetadataKeyEnum.UPDATED));
// assertEquals("1", parsed.getId().getVersionIdPart()); assertEquals("searchset", parsed.getType().getValue());
// assertEquals(new InstantDt("2014-08-18T01:43:30Z"), assertEquals(3, parsed.getTotalResults().getValue().intValue());
// parsed.getResourceMetadata().get(ResourceMetadataKeyEnum.UPDATED));
// assertEquals("searchset", parsed.getType().getValue()); assertEquals(2, parsed.getEntries().size());
// assertEquals(3, parsed.getTotalResults().getValue().intValue());
// assertEquals("http://example.com/base", parsed.getLinkBase().getValue()); MedicationPrescription p = (MedicationPrescription) parsed.getEntries().get(0).getResource();
// assertEquals("https://example.com/base/MedicationPrescription?patient=347&searchId=ff15fd40-ff71-4b48-b366-09c706bed9d0&page=2", assertEquals("Patient/347", p.getPatient().getReference().getValue());
// parsed.getLinkNext().getValue()); assertEquals("2014-08-16T05:31:17Z", ResourceMetadataKeyEnum.UPDATED.get(p).getValueAsString());
// assertEquals("https://example.com/base/MedicationPrescription?patient=347&_include=MedicationPrescription.medication", assertEquals("http://example.com/base/MedicationPrescription/3123/_history/1", p.getId().getValue());
// parsed.getLinkSelf().getValue());
// Medication m = (Medication) parsed.getEntries().get(1).getResource();
// assertEquals(2, parsed.getEntries().size()); assertEquals("http://example.com/base/Medication/example", m.getId().getValue());
// assertEquals("Medication/example", p.getMedication().getReference().getValue());
// MedicationPrescription p = (MedicationPrescription) parsed.getEntries().get(0).getResource(); assertSame(p.getMedication().getResource(), m);
// 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());
String reencoded = ourCtx.newJsonParser().setPrettyPrint(true).encodeBundleToString(parsed); String reencoded = ourCtx.newJsonParser().setPrettyPrint(true).encodeBundleToString(parsed);
ourLog.info(reencoded); ourLog.info(reencoded);
@ -579,6 +604,11 @@ public class JsonParserDstu2Test {
assertEquals("2014-08-16T05:31:17Z", ResourceMetadataKeyEnum.UPDATED.get(p).getValueAsString()); assertEquals("2014-08-16T05:31:17Z", ResourceMetadataKeyEnum.UPDATED.get(p).getValueAsString());
assertEquals("http://example.com/base/MedicationPrescription/3123/_history/1", p.getId().getValue()); 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); String reencoded = ourCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(parsed);
ourLog.info(reencoded); ourLog.info(reencoded);

View File

@ -405,6 +405,10 @@ public class XmlParserDstu2Test {
assertEquals("2014-08-16T05:31:17Z", ResourceMetadataKeyEnum.UPDATED.get(p).getValueAsString()); assertEquals("2014-08-16T05:31:17Z", ResourceMetadataKeyEnum.UPDATED.get(p).getValueAsString());
assertEquals("http://example.com/base/MedicationPrescription/3123/_history/1", p.getId().getValue()); 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); String reencoded = ourCtx.newXmlParser().setPrettyPrint(true).encodeBundleToString(parsed);
ourLog.info(reencoded); ourLog.info(reencoded);
@ -437,6 +441,10 @@ public class XmlParserDstu2Test {
assertEquals("http://example.com/base/MedicationPrescription/3123/_history/1", p.getId().getValue()); assertEquals("http://example.com/base/MedicationPrescription/3123/_history/1", p.getId().getValue());
// assertEquals("3123", 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); String reencoded = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(parsed);
ourLog.info(reencoded); ourLog.info(reencoded);

View File

@ -52,7 +52,7 @@ public class ClientServerValidationTestDstu2 {
} }
@Test @Test
public void testServerReturnsAppropriateVersionForDstu2() throws Exception { public void testServerReturnsAppropriateVersionForDstu2_040() throws Exception {
Conformance conf = new Conformance(); Conformance conf = new Conformance();
conf.setFhirVersion("0.4.0"); conf.setFhirVersion("0.4.0");
final String confResource = myCtx.newXmlParser().encodeResourceToString(conf); final String confResource = myCtx.newXmlParser().encodeResourceToString(conf);
@ -88,6 +88,43 @@ public class ClientServerValidationTestDstu2 {
verify(myHttpClient, times(4)).execute(Matchers.any(HttpUriRequest.class)); 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 @Test
public void testServerReturnsWrongVersionForDstu2() throws Exception { public void testServerReturnsWrongVersionForDstu2() throws Exception {
Conformance conf = new Conformance(); 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). server behind an Apache proxy (e.g. for load balancing or other reasons).
Thanks to Bill de Beaubien for contributing! Thanks to Bill de Beaubien for contributing!
</action> </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>
<release version="0.9" date="2015-Mar-14"> <release version="0.9" date="2015-Mar-14">
<action type="add"> <action type="add">