Returned resource objects from server methods should not be modified

while converting to a bundle
This commit is contained in:
James Agnew 2014-11-20 14:42:24 -05:00
parent f632d119b4
commit 06a1e459d4
7 changed files with 249 additions and 236 deletions

View File

@ -1,75 +0,0 @@
package ca.uhn.fhir.model.base.resource;
/*
* #%L
* HAPI FHIR - Core Library
* %%
* Copyright (C) 2014 University Health Network
* %%
* 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.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
import java.util.List;
import ca.uhn.fhir.model.api.BaseIdentifiableElement;
import ca.uhn.fhir.model.api.BaseResource;
import ca.uhn.fhir.model.api.IResource;
import ca.uhn.fhir.model.api.IResourceBlock;
import ca.uhn.fhir.model.base.composite.BaseCodingDt;
import ca.uhn.fhir.model.primitive.CodeDt;
import ca.uhn.fhir.model.primitive.StringDt;
public abstract class BaseOperationOutcome extends BaseResource implements IResource {
public abstract BaseIssue addIssue();
public abstract List<? extends BaseIssue> getIssue();
public abstract BaseIssue getIssueFirstRep();
public static abstract class BaseIssue extends BaseIdentifiableElement implements IResourceBlock {
<<<<<<< HEAD
public abstract CodeDt getSeverityElement();
=======
public abstract CodeDt getSeverityElement();
>>>>>>> d22a35788f57e9f7ce64bc8afc2ee7eaf29d94f2
public abstract StringDt getDetailsElement();
public abstract BaseCodingDt getType();
<<<<<<< HEAD
public abstract BaseIssue addLocation( String theString);
=======
public abstract BaseIssue addLocation(String theString);
>>>>>>> d22a35788f57e9f7ce64bc8afc2ee7eaf29d94f2
public abstract BaseIssue setDetails(String theString);
public abstract StringDt getLocationFirstRep();
<<<<<<< HEAD
}
=======
}
>>>>>>> d22a35788f57e9f7ce64bc8afc2ee7eaf29d94f2
}

View File

@ -1009,8 +1009,7 @@ public class RestfulServer extends HttpServlet {
}
if (theServer.getAddProfileTag() != AddProfileTagEnum.NEVER) {
for (int i = 0; i < resourceList.size(); i++) {
IResource nextRes = resourceList.get(i);
for (IResource nextRes : resourceList) {
RuntimeResourceDefinition def = theServer.getFhirContext().getResourceDefinition(nextRes);
if (theServer.getAddProfileTag() == AddProfileTagEnum.ALWAYS || !def.isStandardProfile()) {
addProfileToBundleEntry(theServer.getFhirContext(), nextRes);
@ -1088,7 +1087,7 @@ public class RestfulServer extends HttpServlet {
continue;
}
IdDt id = nextRes.getId().toVersionless();
IdDt id = nextRes.getId();
if (id.hasResourceType() == false) {
String resName = theContext.getResourceDefinition(nextRes).getName();
id = id.withResourceType(resName);
@ -1099,8 +1098,6 @@ public class RestfulServer extends HttpServlet {
addedResourcesThisPass.add(nextRes);
}
nextRef.setResource(null);
nextRef.setReference(id);
}
}
}

View File

@ -43,93 +43,33 @@ import ca.uhn.fhir.parser.DataFormatException;
public class FhirTerser {
private FhirContext myContext;
public FhirTerser(FhirContext theContext) {
super();
myContext = theContext;
}
private FhirContext myContext;
public BaseRuntimeChildDefinition getDefinition(Class<? extends IResource> theResourceType, String thePath) {
RuntimeResourceDefinition def = myContext.getResourceDefinition(theResourceType);
BaseRuntimeElementCompositeDefinition<?> currentDef = def;
List<String> parts = Arrays.asList(thePath.split("\\."));
List<String> subList = parts.subList(1, parts.size());
if (subList.size() < 1) {
throw new ConfigurationException("Invalid path: " + thePath);
}
return getDefinition(currentDef, subList);
}
private BaseRuntimeChildDefinition getDefinition(BaseRuntimeElementCompositeDefinition<?> theCurrentDef, List<String> theSubList) {
BaseRuntimeChildDefinition nextDef = theCurrentDef.getChildByNameOrThrowDataFormatException(theSubList.get(0));
if (theSubList.size() == 1) {
return nextDef;
} else {
BaseRuntimeElementCompositeDefinition<?> cmp = (BaseRuntimeElementCompositeDefinition<?>) nextDef.getChildByName(theSubList.get(0));
return getDefinition(cmp, theSubList.subList(1, theSubList.size()));
}
}
public List<Object> getValues(IResource theResource, String thePath) {
RuntimeResourceDefinition def = myContext.getResourceDefinition(theResource);
BaseRuntimeElementCompositeDefinition<?> currentDef = def;
Object currentObj = theResource;
List<String> parts = Arrays.asList(thePath.split("\\."));
List<String> subList = parts.subList(1, parts.size());
if (subList.size() < 1) {
throw new ConfigurationException("Invalid path: " + thePath);
}
return getValues(currentDef, currentObj, subList);
}
private List<Object> getValues(BaseRuntimeElementCompositeDefinition<?> theCurrentDef, Object theCurrentObj, List<String> theSubList) {
String name = theSubList.get(0);
BaseRuntimeChildDefinition nextDef = theCurrentDef.getChildByNameOrThrowDataFormatException(name);
List<? extends IElement> values = nextDef.getAccessor().getValues(theCurrentObj);
List<Object> retVal = new ArrayList<Object>();
if (theSubList.size() == 1) {
retVal.addAll(values);
} else {
for (IElement nextElement : values) {
BaseRuntimeElementCompositeDefinition<?> nextChildDef = (BaseRuntimeElementCompositeDefinition<?>) myContext.getElementDefinition(nextElement.getClass());
List<?> foundValues = getValues(nextChildDef, nextElement, theSubList.subList(1, theSubList.size()));
retVal.addAll(foundValues);
private <T extends IElement> void addUndeclaredExtensions(IElement theElement, BaseRuntimeElementDefinition<?> theDefinition, BaseRuntimeChildDefinition theChildDefinition,
IModelVisitor theCallback) {
if (theElement instanceof ISupportsUndeclaredExtensions) {
ISupportsUndeclaredExtensions containingElement = (ISupportsUndeclaredExtensions) theElement;
for (ExtensionDt nextExt : containingElement.getUndeclaredExtensions()) {
theCallback.acceptUndeclaredExtension(containingElement, theChildDefinition, theDefinition, nextExt);
addUndeclaredExtensions(nextExt, theDefinition, theChildDefinition, theCallback);
}
}
return retVal;
}
/**
* Visit all elements in a given resource
*
* @param theResource The resource to visit
* @param theVisitor The visitor
*/
public void visit(IResource theResource, IModelVisitor theVisitor) {
BaseRuntimeElementCompositeDefinition<?> def = myContext.getResourceDefinition(theResource);
visit(theResource, null, def, theVisitor);
}
/**
* Returns a list containing all child elements (including the resource itself) which are <b>non-empty</b> and are
* either of the exact type specified, or are a subclass of that type.
* Returns a list containing all child elements (including the resource itself) which are <b>non-empty</b> and are either of the exact type specified, or are a subclass of that type.
* <p>
* For example, specifying a type of {@link StringDt} would return all non-empty string instances within the
* message. Specifying a type of {@link IResource} would return the resource itself, as well as any contained
* resources.
* For example, specifying a type of {@link StringDt} would return all non-empty string instances within the message. Specifying a type of {@link IResource} would return the resource itself, as
* well as any contained resources.
* </p>
* <p>
* Note on scope: This method will descend into any contained resources ({@link IResource#getContained()}) as well, but will not
* decend into linked resources (e.g. {@link ResourceReferenceDt#getResource()})
* Note on scope: This method will descend into any contained resources ({@link IResource#getContained()}) as well, but will not decend into linked resources (e.g.
* {@link ResourceReferenceDt#getResource()})
* </p>
*
* @param theResource
@ -156,7 +96,8 @@ public class FhirTerser {
@SuppressWarnings("unchecked")
@Override
public void acceptUndeclaredExtension(ISupportsUndeclaredExtensions theContainingElement, BaseRuntimeChildDefinition theChildDefinition, BaseRuntimeElementDefinition<?> theDefinition, ExtensionDt theNextExt) {
public void acceptUndeclaredExtension(ISupportsUndeclaredExtensions theContainingElement, BaseRuntimeChildDefinition theChildDefinition, BaseRuntimeElementDefinition<?> theDefinition,
ExtensionDt theNextExt) {
if (theType.isAssignableFrom(theNextExt.getClass())) {
retVal.add((T) theNextExt);
}
@ -168,25 +109,85 @@ public class FhirTerser {
return retVal;
}
private BaseRuntimeChildDefinition getDefinition(BaseRuntimeElementCompositeDefinition<?> theCurrentDef, List<String> theSubList) {
BaseRuntimeChildDefinition nextDef = theCurrentDef.getChildByNameOrThrowDataFormatException(theSubList.get(0));
if (theSubList.size() == 1) {
return nextDef;
} else {
BaseRuntimeElementCompositeDefinition<?> cmp = (BaseRuntimeElementCompositeDefinition<?>) nextDef.getChildByName(theSubList.get(0));
return getDefinition(cmp, theSubList.subList(1, theSubList.size()));
}
}
public BaseRuntimeChildDefinition getDefinition(Class<? extends IResource> theResourceType, String thePath) {
RuntimeResourceDefinition def = myContext.getResourceDefinition(theResourceType);
BaseRuntimeElementCompositeDefinition<?> currentDef = def;
List<String> parts = Arrays.asList(thePath.split("\\."));
List<String> subList = parts.subList(1, parts.size());
if (subList.size() < 1) {
throw new ConfigurationException("Invalid path: " + thePath);
}
return getDefinition(currentDef, subList);
}
private List<Object> getValues(BaseRuntimeElementCompositeDefinition<?> theCurrentDef, Object theCurrentObj, List<String> theSubList) {
String name = theSubList.get(0);
BaseRuntimeChildDefinition nextDef = theCurrentDef.getChildByNameOrThrowDataFormatException(name);
List<? extends IElement> values = nextDef.getAccessor().getValues(theCurrentObj);
List<Object> retVal = new ArrayList<Object>();
if (theSubList.size() == 1) {
retVal.addAll(values);
} else {
for (IElement nextElement : values) {
BaseRuntimeElementCompositeDefinition<?> nextChildDef = (BaseRuntimeElementCompositeDefinition<?>) myContext.getElementDefinition(nextElement.getClass());
List<?> foundValues = getValues(nextChildDef, nextElement, theSubList.subList(1, theSubList.size()));
retVal.addAll(foundValues);
}
}
return retVal;
}
public List<Object> getValues(IResource theResource, String thePath) {
RuntimeResourceDefinition def = myContext.getResourceDefinition(theResource);
BaseRuntimeElementCompositeDefinition<?> currentDef = def;
Object currentObj = theResource;
List<String> parts = Arrays.asList(thePath.split("\\."));
List<String> subList = parts.subList(1, parts.size());
if (subList.size() < 1) {
throw new ConfigurationException("Invalid path: " + thePath);
}
return getValues(currentDef, currentObj, subList);
}
private <T extends IElement> void visit(IElement theElement, BaseRuntimeChildDefinition theChildDefinition, BaseRuntimeElementDefinition<?> theDefinition, IModelVisitor theCallback) {
theCallback.acceptElement(theElement, theChildDefinition, theDefinition);
addUndeclaredExtensions(theElement, theDefinition, theChildDefinition, theCallback);
// if (theElement.isEmpty()) {
// return;
// }
// if (theElement.isEmpty()) {
// return;
// }
switch (theDefinition.getChildType()) {
case PRIMITIVE_XHTML:
case PRIMITIVE_DATATYPE:
// These are primitive types
break;
case RESOURCE_REF:
ResourceReferenceDt resRefDt = (ResourceReferenceDt)theElement;
ResourceReferenceDt resRefDt = (ResourceReferenceDt) theElement;
if (resRefDt.getReference().getValue() == null && resRefDt.getResource() != null) {
IResource theResource = resRefDt.getResource();
BaseRuntimeElementCompositeDefinition<?> def = myContext.getResourceDefinition(theResource);
visit(theResource, null, def, theCallback);
if (theResource.getId() == null || theResource.getId().isEmpty() || theResource.getId().isLocal()) {
BaseRuntimeElementCompositeDefinition<?> def = myContext.getResourceDefinition(theResource);
visit(theResource, null, def, theCallback);
}
}
break;
case RESOURCE_BLOCK:
@ -205,7 +206,7 @@ public class FhirTerser {
}
BaseRuntimeElementDefinition<?> childElementDef;
childElementDef = nextChild.getChildElementDefinitionByDatatype(nextValue.getClass());
if (childElementDef == null) {
StringBuilder b = new StringBuilder();
b.append("Found value of type[");
@ -244,14 +245,17 @@ public class FhirTerser {
}
}
private <T extends IElement> void addUndeclaredExtensions(IElement theElement, BaseRuntimeElementDefinition<?> theDefinition, BaseRuntimeChildDefinition theChildDefinition, IModelVisitor theCallback) {
if (theElement instanceof ISupportsUndeclaredExtensions) {
ISupportsUndeclaredExtensions containingElement = (ISupportsUndeclaredExtensions) theElement;
for (ExtensionDt nextExt : containingElement.getUndeclaredExtensions()) {
theCallback.acceptUndeclaredExtension(containingElement, theChildDefinition, theDefinition, nextExt);
addUndeclaredExtensions(nextExt, theDefinition, theChildDefinition, theCallback);
}
}
/**
* Visit all elements in a given resource
*
* @param theResource
* The resource to visit
* @param theVisitor
* The visitor
*/
public void visit(IResource theResource, IModelVisitor theVisitor) {
BaseRuntimeElementCompositeDefinition<?> def = myContext.getResourceDefinition(theResource);
visit(theResource, null, def, theVisitor);
}
}

View File

@ -1,14 +1,22 @@
package ca.uhn.fhir.rest.server;
import static org.apache.commons.lang3.StringUtils.defaultString;
import static org.hamcrest.Matchers.containsString;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertThat;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.model.api.BundleEntry;
import ca.uhn.fhir.model.api.IResource;
import ca.uhn.fhir.model.dstu.composite.ResourceReferenceDt;
import ca.uhn.fhir.model.dstu.resource.*;
import ca.uhn.fhir.model.dstu.resource.Conformance.RestResource;
import ca.uhn.fhir.model.dstu.resource.Conformance.RestResourceSearchParam;
import ca.uhn.fhir.model.dstu.valueset.ResourceTypeEnum;
import ca.uhn.fhir.model.primitive.IdDt;
import ca.uhn.fhir.rest.annotation.IdParam;
import ca.uhn.fhir.rest.annotation.OptionalParam;
import ca.uhn.fhir.rest.annotation.Read;
import ca.uhn.fhir.rest.annotation.Search;
import ca.uhn.fhir.rest.param.ReferenceParam;
import ca.uhn.fhir.rest.param.StringParam;
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
import ca.uhn.fhir.util.PortUtil;
import org.apache.commons.io.IOUtils;
import org.apache.http.HttpResponse;
import org.apache.http.client.methods.HttpGet;
@ -22,33 +30,55 @@ import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.model.api.BundleEntry;
import ca.uhn.fhir.model.api.IResource;
import ca.uhn.fhir.model.dstu.resource.Conformance;
import ca.uhn.fhir.model.dstu.resource.Conformance.RestResource;
import ca.uhn.fhir.model.dstu.resource.Conformance.RestResourceSearchParam;
import ca.uhn.fhir.model.dstu.resource.Location;
import ca.uhn.fhir.model.dstu.resource.Organization;
import ca.uhn.fhir.model.dstu.resource.Patient;
import ca.uhn.fhir.model.dstu.valueset.ResourceTypeEnum;
import ca.uhn.fhir.rest.annotation.OptionalParam;
import ca.uhn.fhir.rest.annotation.Search;
import ca.uhn.fhir.rest.param.ReferenceParam;
import ca.uhn.fhir.rest.param.StringParam;
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
import ca.uhn.fhir.util.PortUtil;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;
import static org.apache.commons.lang3.StringUtils.defaultString;
import static org.hamcrest.Matchers.containsString;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertThat;
/**
* Created by dsotnikov on 2/25/2014.
*/
public class ReferenceParameterTest {
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(ReferenceParameterTest.class);
private static CloseableHttpClient ourClient;
private static int ourPort;
private static Server ourServer;
private static FhirContext ourCtx;
@AfterClass
public static void afterClass() throws Exception {
ourServer.stop();
}
@BeforeClass
public static void beforeClass() throws Exception {
ourPort = PortUtil.findFreePort();
ourServer = new Server(ourPort);
DummyPatientResourceProvider patientProvider = new DummyPatientResourceProvider();
ServletHandler proxyHandler = new ServletHandler();
RestfulServer servlet = new RestfulServer();
ourCtx = servlet.getFhirContext();
servlet.setResourceProviders(patientProvider, new DummyOrganizationResourceProvider(), new DummyLocationResourceProvider());
ServletHolder servletHolder = new ServletHolder(servlet);
proxyHandler.addServletWithMapping(servletHolder, "/*");
ourServer.setHandler(proxyHandler);
ourServer.start();
PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager(5000, TimeUnit.MILLISECONDS);
HttpClientBuilder builder = HttpClientBuilder.create();
builder.setConnectionManager(connectionManager);
ourClient = builder.build();
ourCtx = servlet.getFhirContext();
}
@Test
public void testSearchWithValue() throws Exception {
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?" + Patient.SP_PROVIDER + "=123");
@ -66,6 +96,42 @@ public class ReferenceParameterTest {
assertEquals("2", p.getName().get(2).getFamilyFirstRep().getValue());
}
@Test
public void testSearchReturnVersionedReferenceInResponse() throws Exception {
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?_query=findPatientWithVersion");
HttpResponse status = ourClient.execute(httpGet);
String responseContent = IOUtils.toString(status.getEntity().getContent());
IOUtils.closeQuietly(status.getEntity().getContent());
assertEquals(200, status.getStatusLine().getStatusCode());
List<BundleEntry> entries = ourCtx.newXmlParser().parseBundle(responseContent).getEntries();
assertEquals(2, entries.size());
Patient p = (Patient) entries.get(0).getResource();
assertEquals(0, p.getContained().getContainedResources().size());
assertEquals("22", p.getId().getIdPart());
assertEquals("33", p.getId().getVersionIdPart());
assertEquals("44", p.getManagingOrganization().getReference().getIdPart());
assertEquals("55", p.getManagingOrganization().getReference().getVersionIdPart());
}
@Test
public void testReadReturnVersionedReferenceInResponse() throws Exception {
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient/22");
HttpResponse status = ourClient.execute(httpGet);
String responseContent = IOUtils.toString(status.getEntity().getContent());
IOUtils.closeQuietly(status.getEntity().getContent());
assertEquals(200, status.getStatusLine().getStatusCode());
Patient p = ourCtx.newXmlParser().parseResource(Patient.class, responseContent);
assertThat(status.getFirstHeader("Content-Location").getValue(), containsString("Patient/22/_history/33"));
assertEquals("44", p.getManagingOrganization().getReference().getIdPart());
assertEquals("55", p.getManagingOrganization().getReference().getVersionIdPart());
}
@Test
public void testSearchWithValueAndType() throws Exception {
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?" + Patient.SP_PROVIDER + ":Organization=123");
@ -129,7 +195,7 @@ public class ReferenceParameterTest {
assertThat(responseContent, containsString("value=\"thePartOfId po123 null\""));
assertThat(responseContent, containsString("value=\"thePartOfName poname\""));
}
@Test
public void testSearchWithMultipleParamsOfTheSameName4() throws Exception {
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Organization?partof.fooChain=po123&partof.name=poname");
@ -160,7 +226,7 @@ public class ReferenceParameterTest {
assertEquals(200, status.getStatusLine().getStatusCode());
assertThat(responseContent, containsString("value=\"theBarId Organization/po123 bar\""));
}
@Test
public void testSearchWithMultipleParamsOfTheSameName7() throws Exception {
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Organization?partof:Organization=po123");
@ -179,7 +245,6 @@ public class ReferenceParameterTest {
assertEquals(400, status.getStatusLine().getStatusCode());
}
@Test
public void testSearchWithValueAndChain() throws Exception {
{
@ -198,8 +263,6 @@ public class ReferenceParameterTest {
}
}
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(ReferenceParameterTest.class);
@Test
public void testParamTypesInConformanceStatement() throws Exception {
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/metadata?_pretty=true");
@ -222,35 +285,6 @@ public class ReferenceParameterTest {
assertEquals(ResourceTypeEnum.ORGANIZATION, param.getTarget().get(0).getValueAsEnum());
}
@AfterClass
public static void afterClass() throws Exception {
ourServer.stop();
}
@BeforeClass
public static void beforeClass() throws Exception {
ourPort = PortUtil.findFreePort();
ourServer = new Server(ourPort);
DummyPatientResourceProvider patientProvider = new DummyPatientResourceProvider();
ServletHandler proxyHandler = new ServletHandler();
RestfulServer servlet = new RestfulServer();
ourCtx = servlet.getFhirContext();
servlet.setResourceProviders(patientProvider, new DummyOrganizationResourceProvider(), new DummyLocationResourceProvider());
ServletHolder servletHolder = new ServletHolder(servlet);
proxyHandler.addServletWithMapping(servletHolder, "/*");
ourServer.setHandler(proxyHandler);
ourServer.start();
PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager(5000, TimeUnit.MILLISECONDS);
HttpClientBuilder builder = HttpClientBuilder.create();
builder.setConnectionManager(connectionManager);
ourClient = builder.build();
ourCtx = servlet.getFhirContext();
}
public static class DummyOrganizationResourceProvider implements IResourceProvider {
@Override
@ -349,6 +383,34 @@ public class ReferenceParameterTest {
*/
public static class DummyPatientResourceProvider implements IResourceProvider {
@Search(queryName="findPatientWithVersion")
public List<Patient> findPatientWithVersion() {
ArrayList<Patient> retVal = new ArrayList<Patient>();
Patient p = createPatient();
retVal.add(p);
return retVal;
}
@Read
public Patient read(@IdParam IdDt theId) {
return createPatient();
}
private Patient createPatient() {
Patient p = new Patient();
p.setId("Patient/22/_history/33");
p.addIdentifier("urn:foo", "findPatientWithVersion");
Observation org = new Observation();
org.setId("Observation/44/_history/55");
p.setManagingOrganization(new ResourceReferenceDt(org));
return p;
}
@Search
public List<Patient> findPatient(@OptionalParam(name = Patient.SP_PROVIDER, targetTypes = { Organization.class }) ReferenceParam theParam) {
ArrayList<Patient> retVal = new ArrayList<Patient>();

View File

@ -109,6 +109,11 @@
<id>petromykhailysyn</id>
<name>Petro Mykhailyshyn</name>
</developer>
<developer>
<id>tahurac</id>
<name>Tahura Chaudhry</name>
<organization>University Health Network</organization>
</developer>
</developers>
<licenses>

View File

@ -7,7 +7,7 @@
</properties>
<body>
<release version="0.8" date="TBD">
<action tyle="add">
<action type="add">
<![CDATA[<b>API CHANGE:</b>]]> The "FHIR structures" for DSTU1 (the classes which model the
resources and composite datatypes) have been moved out of the core JAR into their
own JAR, in order to allow support for DEV resources, and DSTU2 resources when thast
@ -39,7 +39,7 @@
defined extension which was of a composite type. Thanks to Bill de Beaubien for the pull request!
</action>
<action type="add" issue="44" dev="petromykhailysyn">
Remove unnessecary IOException from narrative generator API. Thanks to
Remove unnecessary IOException from narrative generator API. Thanks to
Petro Mykhailysyn for the pull request!
</action>
<action type="add" issue="48" dev="wdebeau1">
@ -105,7 +105,8 @@
<action type="add">
When using Generic Client, if performing a
<![CDATA[create]]> or <![CDATA[update]]> operation using a String as the resource body,
the client will auto-detect the FHIR encoding style and send an appropriate Content-Type header.
the client will auto-detect the FHIR encoding style and send an appropriate
<![CDATA[Content-Type]]> header.
</action>
<action type="fix" issue="52">
JPA module (and public HAPI-FHIR test server) were unable to process resource types
@ -117,7 +118,7 @@
Generic/Fluent Client "create" and "update" method requests were not setting a content type header
</action>
<action type="add" issue="53" dev="petromykhailysyn">
DateDt left precision value as null in the constructor
DateDt left precision value as <![CDATA[null]]> in the constructor
<![CDATA[DateDt(Date)]]>.
</action>
<action type="fix">
@ -126,6 +127,25 @@
"[base url]/Patient/123" but if the RP returns ID "http://foo/Patient/123" the ID will be
returned exactly as is. Thanks to Bill de Beaubien for the suggestion!
</action>
<action type="fix" issue="55">
JPA module Transaction operation was not correctly replacing logical IDs
beginning with "cid:" with server assigned IDs, as required by the
specification.
</action>
<action type="fix" dev="tahurac">
<![CDATA[FhirTerser]]> did not visit or find children in contained resources when
searching a resource. This caused server implementations to not always return contained
resources when they are included with a resource being returned.
</action>
<action type="add" dev="lmds">
Add a method <![CDATA[String IResource#getResourceName()]]> which returns the name of the
resource in question (e.g. "Patient", or "Observation"). This is intended as a
convenience to users.
</action>
<action type="fix">
Do not strip version from resource references in resources returned
from server search methods. Thanks to Bill de Beaubien for reporting!
</action>
</release>
<release version="0.7" date="2014-Oct-23">
<action type="add" issue="30">
@ -310,7 +330,7 @@
update. This has no effect other than to switch between the HTTP 200 and HTTP 201 status codes on the
response, but this may be useful in some circumstances.
</action>
<action type="fix">
<action type="fix" dev="tahurac">
Annotation client search methods with a specific resource type (e.g. List&lt;Patient&gt; search())
won't return any resources that aren't of the correct type that are received in a response
bundle (generally these are referenced resources, so they are populated in the reference fields instead).

View File

@ -97,7 +97,7 @@ patient.getManagingOrganization().setReference("Organization/124362");]]></sourc
To do this, you can implement your server method to simply return
<code>List&lt;IResource&gt;</code> and then simply add your extra resources to
the list. Another technique however, is to populate the reference as shown
in the example above, but ensure that the referenced resource has an ID set.
in the example below, but ensure that the referenced resource has an ID set.
</p>
<p>