From dd8b1cd97983dc80c33f2329542defb9edc8aed8 Mon Sep 17 00:00:00 2001 From: James Agnew Date: Wed, 27 Jul 2016 18:15:09 -0400 Subject: [PATCH] Use corrrect types from client --- hapi-fhir-android/pom.xml | 42 +----- .../java/ca/uhn/fhir/android/BuiltJarIT.java | 22 +-- .../ca/uhn/fhir/rest/client/BaseClient.java | 39 ------ .../fhir/rest/method/BaseMethodBinding.java | 7 +- .../BaseResourceReturningMethodBinding.java | 61 ++++---- .../rest/method/GetTagsMethodBinding.java | 2 +- .../ca/uhn/fhir/rest/method/MethodUtil.java | 87 ++++-------- .../fhir/rest/method/ReadMethodBinding.java | 2 +- .../main/java/ca/uhn/fhir/util/XmlUtil.java | 130 +++++++++--------- .../fhir/rest/client/BinaryClientTest.java | 20 +-- .../rest/client/LoggingInterceptorTest.java | 23 +++- .../rest/client/GenericClientDstu3Test.java | 72 ++++++++-- .../client/NonGenericClientDstu3Test.java | 88 ++++++++++-- src/changes/changes.xml | 4 + 14 files changed, 316 insertions(+), 283 deletions(-) diff --git a/hapi-fhir-android/pom.xml b/hapi-fhir-android/pom.xml index e3afc0a4db6..a1757b4d76e 100644 --- a/hapi-fhir-android/pom.xml +++ b/hapi-fhir-android/pom.xml @@ -26,26 +26,19 @@ test - ca.uhn.hapi.fhir hapi-fhir-base 2.0-SNAPSHOT - commons-codec commons-codec + + org.codehaus.woodstox + woodstox-core-asl + @@ -90,19 +83,6 @@ org.apache.commons commons-lang3 - - - - javax.servlet - javax.servlet-api - compile - - @@ -118,6 +98,7 @@ org.apache.maven.plugins maven-failsafe-plugin + @@ -148,18 +130,6 @@ ca.uhn.hapi.fhir:hapi-fhir-base - org.glassfish:javax.json - org.codehaus.woodstox:woodstox-core-asl - javax.xml.stream:stax-api - org.codehaus.woodstox:stax2-api - org.glassfish:javax.json - - javax.servlet:javax.servlet-api diff --git a/hapi-fhir-android/src/test/java/ca/uhn/fhir/android/BuiltJarIT.java b/hapi-fhir-android/src/test/java/ca/uhn/fhir/android/BuiltJarIT.java index 77eb16a2709..f14c6534298 100644 --- a/hapi-fhir-android/src/test/java/ca/uhn/fhir/android/BuiltJarIT.java +++ b/hapi-fhir-android/src/test/java/ca/uhn/fhir/android/BuiltJarIT.java @@ -1,15 +1,9 @@ package ca.uhn.fhir.android; -import static org.junit.Assert.*; +import static org.junit.Assert.assertEquals; import java.io.File; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Enumeration; -import java.util.HashSet; -import java.util.Observable; -import java.util.Set; -import java.util.TreeSet; +import java.util.*; import java.util.zip.ZipEntry; import java.util.zip.ZipFile; @@ -18,10 +12,7 @@ import org.apache.commons.io.filefilter.WildcardFileFilter; import org.junit.BeforeClass; import org.junit.Test; -import com.ctc.wstx.stax.WstxInputFactory; - import ca.uhn.fhir.context.FhirContext; -import ca.uhn.fhir.model.dstu.valueset.QuantityCompararatorEnum; import ca.uhn.fhir.model.dstu2.composite.QuantityDt; import ca.uhn.fhir.model.dstu2.resource.Observation; import ca.uhn.fhir.model.dstu2.resource.Patient; @@ -39,7 +30,11 @@ public class BuiltJarIT { @Test public void testParserXml() throws Exception { -// fail("*******: " + WstxInputFactory.class.getProtectionDomain().getCodeSource().getLocation().toString()); + try { + Class.forName("com.ctc.wstx.stax.WstxOutputFactory"); + } catch (ClassNotFoundException e) { + return; + } FhirContext ctx = FhirContext.forDstu2(); @@ -54,8 +49,6 @@ public class BuiltJarIT { @Test public void testParserJson() { - ourLog.info("AAAAA"); - ourLog.info("AAAAA"); FhirContext ctx = FhirContext.forDstu2(); @@ -72,7 +65,6 @@ public class BuiltJarIT { QuantityDt dt = (QuantityDt) p2.getValue(); dt.getComparatorElement().getValueAsEnum(); - QuantityCompararatorEnum.GREATERTHAN.name(); } /** diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/client/BaseClient.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/client/BaseClient.java index 7af96417244..f0a1a32d277 100644 --- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/client/BaseClient.java +++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/client/BaseClient.java @@ -168,15 +168,6 @@ public abstract class BaseClient implements IRestfulClient { return myLastResponseBody; } - /** - * Returns the pretty print flag, which is a request to the server for it to return "pretty printed" responses. Note - * that this is currently a non-standard flag (_pretty) which is supported only by HAPI based servers (and any other - * servers which might implement it). - */ - public Boolean getPrettyPrint() { - return myPrettyPrint; - } - /** * {@inheritDoc} */ @@ -319,22 +310,6 @@ public abstract class BaseClient implements IRestfulClient { if (handlesBinary.isBinary()) { InputStream reader = response.readEntity(); try { - - if (ourLog.isTraceEnabled() || myKeepResponses || theLogRequestAndResponse) { - byte[] responseBytes = IOUtils.toByteArray(reader); - if (myKeepResponses) { - myLastResponse = response; - myLastResponseBody = null; - } - String message = "HTTP " + response.getStatus() + " " + response.getStatusInfo(); - if (theLogRequestAndResponse) { - ourLog.info("Client response: {} - {} bytes", message, responseBytes.length); - } else { - ourLog.trace("Client response: {} - {} bytes", message, responseBytes.length); - } - reader = new ByteArrayInputStream(responseBytes); - } - return handlesBinary.invokeClient(mimeType, reader, response.getStatus(), headers); } finally { IOUtils.closeQuietly(reader); @@ -441,20 +416,6 @@ public abstract class BaseClient implements IRestfulClient { myKeepResponses = theKeepResponses; } - /** - * For now, this is a part of the internal API of HAPI - Use with caution as this method may change! - */ - public void setLastResponse(IHttpResponse theLastResponse) { - myLastResponse = theLastResponse; - } - - /** - * For now, this is a part of the internal API of HAPI - Use with caution as this method may change! - */ - public void setLastResponseBody(String theLastResponseBody) { - myLastResponseBody = theLastResponseBody; - } - /** * Sets the pretty print flag, which is a request to the server for it to return "pretty printed" responses. Note * that this is currently a non-standard flag (_pretty) which is supported only by HAPI based servers (and any other diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/method/BaseMethodBinding.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/method/BaseMethodBinding.java index 8b96fa8230e..b4155cede8d 100644 --- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/method/BaseMethodBinding.java +++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/method/BaseMethodBinding.java @@ -116,7 +116,7 @@ public abstract class BaseMethodBinding implements IClientResponseHandler } - protected IParser createAppropriateParserForParsingResponse(String theResponseMimeType, Reader theResponseReader, int theResponseStatusCode) { + protected IParser createAppropriateParserForParsingResponse(String theResponseMimeType, Reader theResponseReader, int theResponseStatusCode, List> thePreferTypes) { EncodingEnum encoding = EncodingEnum.forContentType(theResponseMimeType); if (encoding == null) { NonFhirResponseException ex = NonFhirResponseException.newInstance(theResponseStatusCode, theResponseMimeType, theResponseReader); @@ -125,6 +125,9 @@ public abstract class BaseMethodBinding implements IClientResponseHandler } IParser parser = encoding.newParser(getContext()); + + parser.setPreferTypes(thePreferTypes); + return parser; } @@ -325,7 +328,7 @@ public abstract class BaseMethodBinding implements IClientResponseHandler ex = new PreconditionFailedException("Server responded with HTTP 412"); break; case Constants.STATUS_HTTP_422_UNPROCESSABLE_ENTITY: - IParser parser = createAppropriateParserForParsingResponse(theResponseMimeType, theResponseReader, theStatusCode); + IParser parser = createAppropriateParserForParsingResponse(theResponseMimeType, theResponseReader, theStatusCode, null); // TODO: handle if something other than OO comes back BaseOperationOutcome operationOutcome = (BaseOperationOutcome) parser.parseResource(theResponseReader); ex = new UnprocessableEntityException(myContext, operationOutcome); diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/method/BaseResourceReturningMethodBinding.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/method/BaseResourceReturningMethodBinding.java index 89921da720d..2ff41a9c355 100644 --- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/method/BaseResourceReturningMethodBinding.java +++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/method/BaseResourceReturningMethodBinding.java @@ -10,7 +10,7 @@ package ca.uhn.fhir.rest.method; * 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 + * 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, @@ -25,15 +25,7 @@ import java.io.IOException; import java.io.Reader; import java.lang.reflect.Method; import java.lang.reflect.Modifier; -import java.util.Collection; -import java.util.Collections; -import java.util.Date; -import java.util.HashSet; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.TreeSet; +import java.util.*; import org.hl7.fhir.instance.model.api.IBaseBundle; import org.hl7.fhir.instance.model.api.IBaseOperationOutcome; @@ -91,7 +83,8 @@ public abstract class BaseResourceReturningMethodBinding extends BaseMethodBindi private MethodReturnTypeEnum myMethodReturnType; private Class myResourceListCollectionType; private String myResourceName; - private Class myResourceType; + private Class myResourceType; + private List> myPreferTypesList; @SuppressWarnings("unchecked") public BaseResourceReturningMethodBinding(Class theReturnResourceType, Method theMethod, FhirContext theContext, Object theProvider) { @@ -137,6 +130,8 @@ public abstract class BaseResourceReturningMethodBinding extends BaseMethodBindi } } } + + myPreferTypesList = createPreferTypesList(); } public MethodReturnTypeEnum getMethodReturnType() { @@ -157,11 +152,11 @@ public abstract class BaseResourceReturningMethodBinding extends BaseMethodBindi @Override public Object invokeClient(String theResponseMimeType, Reader theResponseReader, int theResponseStatusCode, Map> theHeaders) { - IParser parser = createAppropriateParserForParsingResponse(theResponseMimeType, theResponseReader, theResponseStatusCode); + IParser parser = createAppropriateParserForParsingResponse(theResponseMimeType, theResponseReader, theResponseStatusCode, myPreferTypesList); switch (getReturnType()) { case BUNDLE: { - + Bundle dstu1bundle = null; IBaseBundle dstu2bundle = null; List listOfResources = null; @@ -177,7 +172,7 @@ public abstract class BaseResourceReturningMethodBinding extends BaseMethodBindi dstu2bundle = (IBaseBundle) parser.parseResource(type, theResponseReader); listOfResources = BundleUtil.toListOfResources(getContext(), dstu2bundle); } - + switch (getMethodReturnType()) { case BUNDLE: return dstu1bundle; @@ -185,7 +180,7 @@ public abstract class BaseResourceReturningMethodBinding extends BaseMethodBindi return dstu2bundle; case LIST_OF_RESOURCES: if (myResourceListCollectionType != null) { - for (Iterator iter = listOfResources.iterator(); iter.hasNext(); ) { + for (Iterator iter = listOfResources.iterator(); iter.hasNext();) { IBaseResource next = iter.next(); if (!myResourceListCollectionType.isAssignableFrom(next.getClass())) { ourLog.debug("Not returning resource of type {} because it is not a subclass or instance of {}", next.getClass(), myResourceListCollectionType); @@ -243,6 +238,19 @@ public abstract class BaseResourceReturningMethodBinding extends BaseMethodBindi throw new IllegalStateException("Should not get here!"); } + @SuppressWarnings("unchecked") + private List> createPreferTypesList() { + List> preferTypes = null; + if (myResourceListCollectionType != null && IBaseResource.class.isAssignableFrom(myResourceListCollectionType)) { + preferTypes = new ArrayList>(1); + preferTypes.add((Class) myResourceListCollectionType); +// } else if (myResourceType != null) { +// preferTypes = new ArrayList>(1); +// preferTypes.add((Class) myResourceListCollectionType); + } + return preferTypes; + } + @Override public Object invokeServer(IRestfulServer theServer, RequestDetails theRequest) throws BaseServerResponseException, IOException { @@ -250,7 +258,7 @@ public abstract class BaseResourceReturningMethodBinding extends BaseMethodBindi Set summaryMode = RestfulServerUtils.determineSummaryMode(theRequest); if (responseObject.getResource() != null) { - + for (int i = theServer.getInterceptors().size() - 1; i >= 0; i--) { IServerInterceptor next = theServer.getInterceptors().get(i); boolean continueProcessing = next.outgoingResponse(theRequest, responseObject.getResource()); @@ -258,12 +266,12 @@ public abstract class BaseResourceReturningMethodBinding extends BaseMethodBindi return null; } } - + boolean prettyPrint = RestfulServerUtils.prettyPrintResponse(theServer, theRequest); - - return theRequest.getResponse().streamResponseAsResource(responseObject.getResource(), prettyPrint, summaryMode, Constants.STATUS_HTTP_200_OK, null, - theRequest.isRespondGzip(), isAddContentLocationHeader()); - + + return theRequest.getResponse().streamResponseAsResource(responseObject.getResource(), prettyPrint, summaryMode, Constants.STATUS_HTTP_200_OK, null, theRequest.isRespondGzip(), + isAddContentLocationHeader()); + } else { // Is this request coming from a browser String uaHeader = theRequest.getHeader("user-agent"); @@ -271,7 +279,7 @@ public abstract class BaseResourceReturningMethodBinding extends BaseMethodBindi if (uaHeader != null && uaHeader.contains("Mozilla")) { requestIsBrowser = true; } - + for (int i = theServer.getInterceptors().size() - 1; i >= 0; i--) { IServerInterceptor next = theServer.getInterceptors().get(i); boolean continueProcessing = next.outgoingResponse(theRequest, responseObject.getDstu1Bundle()); @@ -356,7 +364,7 @@ public abstract class BaseResourceReturningMethodBinding extends BaseMethodBindi responseObject = new ResourceOrDstu1Bundle(resource); break; - + } else { Set includes = getRequestIncludesFromParams(params); @@ -364,20 +372,21 @@ public abstract class BaseResourceReturningMethodBinding extends BaseMethodBindi if (count == null) { count = result.preferredPageSize(); } - + Integer offsetI = RestfulServerUtils.tryToExtractNamedParameter(theRequest, Constants.PARAM_PAGINGOFFSET); if (offsetI == null || offsetI < 0) { offsetI = 0; } int start = Math.max(0, Math.min(offsetI, result.size() - 1)); - + IVersionSpecificBundleFactory bundleFactory = theServer.getFhirContext().newBundleFactory(); ResponseEncoding responseEncoding = RestfulServerUtils.determineResponseEncodingNoDefault(theRequest, theServer.getDefaultResponseEncoding()); EncodingEnum linkEncoding = theRequest.getParameters().containsKey(Constants.PARAM_FORMAT) && responseEncoding != null ? responseEncoding.getEncoding() : null; boolean prettyPrint = RestfulServerUtils.prettyPrintResponse(theServer, theRequest); - bundleFactory.initializeBundleFromBundleProvider(theServer, result, linkEncoding, theRequest.getFhirServerBase(), linkSelf, prettyPrint, start, count, null, getResponseBundleType(), includes); + bundleFactory.initializeBundleFromBundleProvider(theServer, result, linkEncoding, theRequest.getFhirServerBase(), linkSelf, prettyPrint, start, count, null, getResponseBundleType(), + includes); Bundle bundle = bundleFactory.getDstu1Bundle(); if (bundle != null) { responseObject = new ResourceOrDstu1Bundle(bundle); diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/method/GetTagsMethodBinding.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/method/GetTagsMethodBinding.java index 00d55e79bbd..c8c336da2af 100644 --- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/method/GetTagsMethodBinding.java +++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/method/GetTagsMethodBinding.java @@ -153,7 +153,7 @@ public class GetTagsMethodBinding extends BaseMethodBinding { @Override public TagList invokeClient(String theResponseMimeType, Reader theResponseReader, int theResponseStatusCode, Map> theHeaders) throws BaseServerResponseException { if (theResponseStatusCode == Constants.STATUS_HTTP_200_OK) { - IParser parser = createAppropriateParserForParsingResponse(theResponseMimeType, theResponseReader, theResponseStatusCode); + IParser parser = createAppropriateParserForParsingResponse(theResponseMimeType, theResponseReader, theResponseStatusCode, null); TagList retVal = parser.parseTagList(theResponseReader); return retVal; } else { diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/method/MethodUtil.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/method/MethodUtil.java index 34445b4d835..5b55ef34f98 100644 --- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/method/MethodUtil.java +++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/method/MethodUtil.java @@ -8,80 +8,28 @@ import java.io.PushbackReader; import java.io.Reader; import java.lang.annotation.Annotation; import java.lang.reflect.Method; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.Date; -import java.util.List; -import java.util.Map; +import java.util.*; import java.util.Map.Entry; -import javax.servlet.ServletRequest; -import javax.servlet.ServletResponse; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; - import org.apache.commons.lang3.ObjectUtils; import org.apache.commons.lang3.StringUtils; -import org.hl7.fhir.instance.model.api.IAnyResource; -import org.hl7.fhir.instance.model.api.IBaseMetaType; -import org.hl7.fhir.instance.model.api.IBaseOperationOutcome; -import org.hl7.fhir.instance.model.api.IBaseResource; -import org.hl7.fhir.instance.model.api.IIdType; +import org.hl7.fhir.instance.model.api.*; -import ca.uhn.fhir.context.ConfigurationException; -import ca.uhn.fhir.context.FhirContext; -import ca.uhn.fhir.context.FhirVersionEnum; -import ca.uhn.fhir.context.RuntimeResourceDefinition; -import ca.uhn.fhir.context.RuntimeSearchParam; -import ca.uhn.fhir.model.api.IQueryParameterAnd; -import ca.uhn.fhir.model.api.IQueryParameterOr; -import ca.uhn.fhir.model.api.IQueryParameterType; -import ca.uhn.fhir.model.api.IResource; -import ca.uhn.fhir.model.api.Include; -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.context.*; +import ca.uhn.fhir.model.api.*; import ca.uhn.fhir.model.api.annotation.Description; import ca.uhn.fhir.model.primitive.IdDt; import ca.uhn.fhir.model.primitive.InstantDt; import ca.uhn.fhir.parser.IParser; -import ca.uhn.fhir.rest.annotation.At; -import ca.uhn.fhir.rest.annotation.ConditionalUrlParam; -import ca.uhn.fhir.rest.annotation.Count; -import ca.uhn.fhir.rest.annotation.Elements; -import ca.uhn.fhir.rest.annotation.IdParam; -import ca.uhn.fhir.rest.annotation.IncludeParam; -import ca.uhn.fhir.rest.annotation.Operation; -import ca.uhn.fhir.rest.annotation.OperationParam; -import ca.uhn.fhir.rest.annotation.OptionalParam; -import ca.uhn.fhir.rest.annotation.RequiredParam; -import ca.uhn.fhir.rest.annotation.ResourceParam; -import ca.uhn.fhir.rest.annotation.Search; -import ca.uhn.fhir.rest.annotation.ServerBase; -import ca.uhn.fhir.rest.annotation.Since; -import ca.uhn.fhir.rest.annotation.Sort; -import ca.uhn.fhir.rest.annotation.TagListParam; -import ca.uhn.fhir.rest.annotation.TransactionParam; -import ca.uhn.fhir.rest.annotation.Validate; -import ca.uhn.fhir.rest.annotation.VersionIdParam; +import ca.uhn.fhir.rest.annotation.*; import ca.uhn.fhir.rest.api.MethodOutcome; import ca.uhn.fhir.rest.api.RestOperationTypeEnum; import ca.uhn.fhir.rest.api.SummaryEnum; import ca.uhn.fhir.rest.api.ValidationModeEnum; import ca.uhn.fhir.rest.client.BaseHttpClientInvocation; import ca.uhn.fhir.rest.method.OperationParameter.IOperationParamConverter; -import ca.uhn.fhir.rest.param.CollectionBinder; -import ca.uhn.fhir.rest.param.DateAndListParam; -import ca.uhn.fhir.rest.param.NumberAndListParam; -import ca.uhn.fhir.rest.param.QuantityAndListParam; -import ca.uhn.fhir.rest.param.ReferenceAndListParam; -import ca.uhn.fhir.rest.param.ResourceParameter; +import ca.uhn.fhir.rest.param.*; import ca.uhn.fhir.rest.param.ResourceParameter.Mode; -import ca.uhn.fhir.rest.param.StringAndListParam; -import ca.uhn.fhir.rest.param.TokenAndListParam; -import ca.uhn.fhir.rest.param.TransactionParameter; -import ca.uhn.fhir.rest.param.UriAndListParam; import ca.uhn.fhir.rest.server.Constants; import ca.uhn.fhir.rest.server.EncodingEnum; import ca.uhn.fhir.rest.server.IDynamicSearchResourceProvider; @@ -121,8 +69,17 @@ public class MethodUtil { private static final String LABEL = "label=\""; private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(MethodUtil.class); - private static final String SCHEME = "scheme=\""; + private static final Set ourServletRequestTypes = new HashSet(); + private static final Set ourServletResponseTypes = new HashSet(); + + static { + ourServletRequestTypes.add("javax.servlet.ServletRequest"); + ourServletResponseTypes.add("javax.servlet.ServletResponse"); + ourServletRequestTypes.add("javax.servlet.http.HttpServletRequest"); + ourServletResponseTypes.add("javax.servlet.http.HttpServletResponse"); + } + static void addTagsToPostOrPut(FhirContext theContext, IBaseResource resource, BaseHttpClientInvocation retVal) { if (theContext.getVersion().getVersion().equals(FhirVersionEnum.DSTU1)) { @@ -391,16 +348,22 @@ public class MethodUtil { throw new ConfigurationException("Argument #" + paramIndex + " of Method '" + theMethod.getName() + "' in type '" + theMethod.getDeclaringClass().getCanonicalName() + "' is of an invalid generic type (can not be a collection of a collection of a collection)"); } } - if (parameterType.equals(HttpServletRequest.class) || parameterType.equals(ServletRequest.class)) { + + /* + * Note: for the frst two here, we're using strings instead of static binding + * so that we don't need the java.servlet JAR on the classpath in order to use + * this class + */ + if (ourServletRequestTypes.contains(parameterType.getName())) { param = new ServletRequestParameter(); + } else if (ourServletResponseTypes.contains(parameterType.getName())) { + param = new ServletResponseParameter(); } else if (parameterType.equals(RequestDetails.class)) { param = new RequestDetailsParameter(); } else if (parameterType.equals(IRequestOperationCallback.class)) { param = new RequestOperationCallbackParameter(); } else if (parameterType.equals(SummaryEnum.class)) { param = new SummaryEnumParameter(); - } else if (parameterType.equals(HttpServletResponse.class) || parameterType.equals(ServletResponse.class)) { - param = new ServletResponseParameter(); } else { for (int i = 0; i < annotations.length && param == null; i++) { Annotation nextAnnotation = annotations[i]; diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/method/ReadMethodBinding.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/method/ReadMethodBinding.java index 0636c903b59..e815b37f22e 100644 --- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/method/ReadMethodBinding.java +++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/method/ReadMethodBinding.java @@ -163,7 +163,7 @@ public class ReadMethodBinding extends BaseResourceReturningMethodBinding implem @Override public HttpGetClientInvocation invokeClient(Object[] theArgs) { HttpGetClientInvocation retVal; - IdDt id = ((IdDt) theArgs[myIdIndex]); + IIdType id = ((IIdType) theArgs[myIdIndex]); if (myVersionIdIndex == null) { String resourceName = getResourceName(); if (id.hasVersionIdPart()) { diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/util/XmlUtil.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/util/XmlUtil.java index 878965f4300..98f62579210 100644 --- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/util/XmlUtil.java +++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/util/XmlUtil.java @@ -56,12 +56,12 @@ import ca.uhn.fhir.util.jar.IDependencyLog; * This class contains code adapted from the Apache Axiom project. */ public class XmlUtil { + private static XMLOutputFactory ourFragmentOutputFactory; private static volatile boolean ourHaveLoggedStaxImplementation; private static volatile XMLInputFactory ourInputFactory; private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(XmlUtil.class); - private static volatile XMLOutputFactory ourOutputFactory; - private static XMLOutputFactory ourFragmentOutputFactory; private static Throwable ourNextException; + private static volatile XMLOutputFactory ourOutputFactory; private static final Map VALID_ENTITY_NAMES; private static final ExtendedEntityReplacingXmlResolver XML_RESOLVER = new ExtendedEntityReplacingXmlResolver(); @@ -1519,6 +1519,42 @@ public class XmlUtil { VALID_ENTITY_NAMES = Collections.unmodifiableMap(validEntityNames); } + private static XMLOutputFactory createOutputFactory() throws FactoryConfigurationError { + try { + // Detect if we're running with the Android lib, and force repackaged Woodstox to be used + Class.forName("ca.uhn.fhir.repackage.javax.xml.stream.XMLOutputFactory"); + System.setProperty("javax.xml.stream.XMLOutputFactory", "com.ctc.wstx.stax.WstxOutputFactory"); + } catch (ClassNotFoundException e) { + // ok + } + + XMLOutputFactory outputFactory = XMLOutputFactory.newInstance(); + + if (!ourHaveLoggedStaxImplementation) { + logStaxImplementation(outputFactory.getClass()); + } + + /* + * Note that these properties are Woodstox specific and they cause a crash in environments where SJSXP is + * being used (e.g. glassfish) so we don't set them there. + */ + try { + Class.forName("com.ctc.wstx.stax.WstxOutputFactory"); + if (outputFactory instanceof WstxOutputFactory) { + outputFactory.setProperty(XMLOutputFactory2.P_TEXT_ESCAPER, new MyEscaper()); + } + } catch (ClassNotFoundException e) { + ourLog.debug("WstxOutputFactory (Woodstox) not found on classpath"); + } + return outputFactory; + } + + public static XMLEventWriter createXmlFragmentWriter(Writer theWriter) throws FactoryConfigurationError, XMLStreamException { + XMLOutputFactory outputFactory = getOrCreateFragmentOutputFactory(); + XMLEventWriter retVal = outputFactory.createXMLEventWriter(theWriter); + return retVal; + } + public static XMLEventReader createXmlReader(Reader reader) throws FactoryConfigurationError, XMLStreamException { throwUnitTestExceptionIfConfiguredToDoSo(); @@ -1529,16 +1565,6 @@ public class XmlUtil { return er; } - private static void throwUnitTestExceptionIfConfiguredToDoSo() throws FactoryConfigurationError, XMLStreamException { - if (ourNextException != null) { - if (ourNextException instanceof FactoryConfigurationError) { - throw ((FactoryConfigurationError)ourNextException); - } else { - throw (XMLStreamException)ourNextException; - } - } - } - public static XMLStreamWriter createXmlStreamWriter(Writer theWriter) throws FactoryConfigurationError, XMLStreamException { throwUnitTestExceptionIfConfiguredToDoSo(); @@ -1547,15 +1573,20 @@ public class XmlUtil { return retVal; } - public static XMLEventWriter createXmlFragmentWriter(Writer theWriter) throws FactoryConfigurationError, XMLStreamException { - XMLOutputFactory outputFactory = getOrCreateFragmentOutputFactory(); + public static XMLEventWriter createXmlWriter(Writer theWriter) throws FactoryConfigurationError, XMLStreamException { + XMLOutputFactory outputFactory = getOrCreateOutputFactory(); XMLEventWriter retVal = outputFactory.createXMLEventWriter(theWriter); return retVal; } - public static XMLEventWriter createXmlWriter(Writer theWriter) throws FactoryConfigurationError, XMLStreamException { - XMLOutputFactory outputFactory = getOrCreateOutputFactory(); - XMLEventWriter retVal = outputFactory.createXMLEventWriter(theWriter); + private static XMLOutputFactory getOrCreateFragmentOutputFactory() throws FactoryConfigurationError { + XMLOutputFactory retVal = ourFragmentOutputFactory; + if (retVal == null) { + retVal = createOutputFactory(); + retVal.setProperty(XMLOutputFactory.IS_REPAIRING_NAMESPACES, Boolean.TRUE); + ourFragmentOutputFactory = retVal; + return retVal; + } return retVal; } @@ -1614,17 +1645,6 @@ public class XmlUtil { return ourInputFactory; } - private static XMLOutputFactory getOrCreateFragmentOutputFactory() throws FactoryConfigurationError { - XMLOutputFactory retVal = ourFragmentOutputFactory; - if (retVal == null) { - retVal = createOutputFactory(); - retVal.setProperty(XMLOutputFactory.IS_REPAIRING_NAMESPACES, Boolean.TRUE); - ourFragmentOutputFactory = retVal; - return retVal; - } - return retVal; - } - private static XMLOutputFactory getOrCreateOutputFactory() throws FactoryConfigurationError { if (ourOutputFactory == null) { @@ -1633,36 +1653,6 @@ public class XmlUtil { return ourOutputFactory; } - private static XMLOutputFactory createOutputFactory() throws FactoryConfigurationError { - try { - // Detect if we're running with the Android lib, and force repackaged Woodstox to be used - Class.forName("ca.uhn.fhir.repackage.javax.xml.stream.XMLOutputFactory"); - System.setProperty("javax.xml.stream.XMLOutputFactory", "com.ctc.wstx.stax.WstxOutputFactory"); - } catch (ClassNotFoundException e) { - // ok - } - - XMLOutputFactory outputFactory = XMLOutputFactory.newInstance(); - - if (!ourHaveLoggedStaxImplementation) { - logStaxImplementation(outputFactory.getClass()); - } - - /* - * Note that these properties are Woodstox specific and they cause a crash in environments where SJSXP is - * being used (e.g. glassfish) so we don't set them there. - */ - try { - Class.forName("com.ctc.wstx.stax.WstxOutputFactory"); - if (outputFactory instanceof WstxOutputFactory) { - outputFactory.setProperty(XMLOutputFactory2.P_TEXT_ESCAPER, new MyEscaper()); - } - } catch (ClassNotFoundException e) { - ourLog.debug("WstxOutputFactory (Woodstox) not found on classpath"); - } - return outputFactory; - } - private static void logStaxImplementation(Class theClass) { IDependencyLog logger = DependencyLogFactory.createJarLogger(); if (logger != null) { @@ -1671,6 +1661,23 @@ public class XmlUtil { ourHaveLoggedStaxImplementation = true; } + /** + * FOR UNIT TESTS ONLY - Throw this exception for the next operation + */ + static void setThrowExceptionForUnitTest(Throwable theException) { + ourNextException = theException; + } + + private static void throwUnitTestExceptionIfConfiguredToDoSo() throws FactoryConfigurationError, XMLStreamException { + if (ourNextException != null) { + if (ourNextException instanceof FactoryConfigurationError) { + throw ((FactoryConfigurationError)ourNextException); + } else { + throw (XMLStreamException)ourNextException; + } + } + } + private static final class ExtendedEntityReplacingXmlResolver implements XMLResolver { @Override public Object resolveEntity(String thePublicID, String theSystemID, String theBaseURI, String theNamespace) throws XMLStreamException { @@ -1735,11 +1742,4 @@ public class XmlUtil { } - /** - * FOR UNIT TESTS ONLY - Throw this exception for the next operation - */ - static void setThrowExceptionForUnitTest(Throwable theException) { - ourNextException = theException; - } - } diff --git a/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/rest/client/BinaryClientTest.java b/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/rest/client/BinaryClientTest.java index cee820470a2..7289c601fef 100644 --- a/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/rest/client/BinaryClientTest.java +++ b/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/rest/client/BinaryClientTest.java @@ -38,19 +38,19 @@ import ca.uhn.fhir.util.TestUtil; public class BinaryClientTest { - private FhirContext ctx; - private HttpClient httpClient; + private FhirContext mtCtx; + private HttpClient myHttpClient; private HttpResponse httpResponse; // atom-document-large.xml @Before public void before() { - ctx = FhirContext.forDstu1(); + mtCtx = FhirContext.forDstu1(); - httpClient = mock(HttpClient.class, new ReturnsDeepStubs()); - ctx.getRestfulClientFactory().setHttpClient(httpClient); - ctx.getRestfulClientFactory().setServerValidationMode(ServerValidationModeEnum.NEVER); + myHttpClient = mock(HttpClient.class, new ReturnsDeepStubs()); + mtCtx.getRestfulClientFactory().setHttpClient(myHttpClient); + mtCtx.getRestfulClientFactory().setServerValidationMode(ServerValidationModeEnum.NEVER); httpResponse = mock(HttpResponse.class, new ReturnsDeepStubs()); } @@ -58,12 +58,12 @@ public class BinaryClientTest { @Test public void testRead() throws Exception { ArgumentCaptor capt = ArgumentCaptor.forClass(HttpUriRequest.class); - when(httpClient.execute(capt.capture())).thenReturn(httpResponse); + when(myHttpClient.execute(capt.capture())).thenReturn(httpResponse); when(httpResponse.getStatusLine()).thenReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 200, "OK")); when(httpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", "foo/bar")); when(httpResponse.getEntity().getContent()).thenReturn(new ByteArrayInputStream(new byte[] { 1, 2, 3, 4 })); - IClient client = ctx.newRestfulClient(IClient.class, "http://foo"); + IClient client = mtCtx.newRestfulClient(IClient.class, "http://foo"); Binary resp = client.read(new IdDt("http://foo/Patient/123")); assertEquals(HttpGet.class, capt.getValue().getClass()); @@ -81,12 +81,12 @@ public class BinaryClientTest { res.setContentType("text/plain"); ArgumentCaptor capt = ArgumentCaptor.forClass(HttpUriRequest.class); - when(httpClient.execute(capt.capture())).thenReturn(httpResponse); + when(myHttpClient.execute(capt.capture())).thenReturn(httpResponse); when(httpResponse.getStatusLine()).thenReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 201, "OK")); when(httpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", Constants.CT_FHIR_XML)); when(httpResponse.getEntity().getContent()).thenReturn(new ByteArrayInputStream(new byte[] {})); - IClient client = ctx.newRestfulClient(IClient.class, "http://foo"); + IClient client = mtCtx.newRestfulClient(IClient.class, "http://foo"); client.create(res); assertEquals(HttpPost.class, capt.getValue().getClass()); diff --git a/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/rest/client/LoggingInterceptorTest.java b/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/rest/client/LoggingInterceptorTest.java index 914466450aa..0d14bf586e1 100644 --- a/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/rest/client/LoggingInterceptorTest.java +++ b/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/rest/client/LoggingInterceptorTest.java @@ -74,11 +74,14 @@ public class LoggingInterceptorTest { public void testLogger() throws Exception { System.out.println("Starting testLogger"); IGenericClient client = ourCtx.newRestfulGenericClient("http://localhost:" + ourPort); - client.registerInterceptor(new LoggingInterceptor(true)); + ourCtx.getRestfulClientFactory().setServerValidationMode(ServerValidationModeEnum.NEVER); + + LoggingInterceptor interceptor = new LoggingInterceptor(true); + client.registerInterceptor(interceptor); Patient patient = client.read(Patient.class, "1"); assertFalse(patient.getIdentifierFirstRep().isEmpty()); - verify(myMockAppender, atLeastOnce()).doAppend(argThat(new ArgumentMatcher() { + verify(myMockAppender, times(1)).doAppend(argThat(new ArgumentMatcher() { @Override public boolean matches(final Object argument) { String formattedMessage = ((LoggingEvent) argument).getFormattedMessage(); @@ -86,6 +89,22 @@ public class LoggingInterceptorTest { return formattedMessage.replace("; ", ";").toLowerCase().contains("Content-Type: application/xml+fhir;charset=utf-8".toLowerCase()); } })); + + // Unregister the interceptor + client.unregisterInterceptor(interceptor); + + patient = client.read(Patient.class, "1"); + assertFalse(patient.getIdentifierFirstRep().isEmpty()); + + verify(myMockAppender, times(1)).doAppend(argThat(new ArgumentMatcher() { + @Override + public boolean matches(final Object argument) { + String formattedMessage = ((LoggingEvent) argument).getFormattedMessage(); + System.out.println("Verifying: " + formattedMessage); + return formattedMessage.replace("; ", ";").toLowerCase().contains("Content-Type: application/xml+fhir;charset=utf-8".toLowerCase()); + } + })); + } @AfterClass diff --git a/hapi-fhir-structures-dstu3/src/test/java/ca/uhn/fhir/rest/client/GenericClientDstu3Test.java b/hapi-fhir-structures-dstu3/src/test/java/ca/uhn/fhir/rest/client/GenericClientDstu3Test.java index 7a600e2ce34..9745148593f 100644 --- a/hapi-fhir-structures-dstu3/src/test/java/ca/uhn/fhir/rest/client/GenericClientDstu3Test.java +++ b/hapi-fhir-structures-dstu3/src/test/java/ca/uhn/fhir/rest/client/GenericClientDstu3Test.java @@ -15,11 +15,7 @@ import java.io.IOException; import java.io.InputStream; import java.io.StringReader; import java.nio.charset.Charset; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.Date; -import java.util.List; +import java.util.*; import org.apache.commons.io.IOUtils; import org.apache.commons.io.input.ReaderInputStream; @@ -32,16 +28,8 @@ import org.apache.http.client.methods.HttpEntityEnclosingRequestBase; import org.apache.http.client.methods.HttpUriRequest; import org.apache.http.message.BasicHeader; import org.apache.http.message.BasicStatusLine; -import org.hl7.fhir.dstu3.model.Binary; -import org.hl7.fhir.dstu3.model.Bundle; +import org.hl7.fhir.dstu3.model.*; import org.hl7.fhir.dstu3.model.Bundle.BundleType; -import org.hl7.fhir.dstu3.model.Conformance; -import org.hl7.fhir.dstu3.model.Device; -import org.hl7.fhir.dstu3.model.Encounter; -import org.hl7.fhir.dstu3.model.Observation; -import org.hl7.fhir.dstu3.model.OperationOutcome; -import org.hl7.fhir.dstu3.model.Parameters; -import org.hl7.fhir.dstu3.model.Patient; import org.hl7.fhir.instance.model.api.IBaseResource; import org.junit.AfterClass; import org.junit.Before; @@ -102,6 +90,62 @@ public class GenericClientDstu3Test { return "HAPI-FHIR/" + VersionUtil.getVersion() + " (FHIR Client; FHIR " + FhirVersionEnum.DSTU3.getFhirVersionString() + "/DSTU3; apache)"; } + @Test + public void testValidateCustomTypeFromClientSearch() throws Exception { + IParser p = ourCtx.newXmlParser(); + + Bundle b = new Bundle(); + + MyPatientWithExtensions patient = new MyPatientWithExtensions(); + patient.setId("123"); + patient.getText().setDivAsString("OK!"); + b.addEntry().setResource(patient); + + + final String respString = p.encodeResourceToString(b); + ArgumentCaptor capt = ArgumentCaptor.forClass(HttpUriRequest.class); + when(myHttpClient.execute(capt.capture())).thenReturn(myHttpResponse); + 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() { + @Override + public ReaderInputStream answer(InvocationOnMock theInvocation) throws Throwable { + return new ReaderInputStream(new StringReader(respString), Charset.forName("UTF-8")); + } + }); + + IGenericClient client = ourCtx.newRestfulGenericClient("http://example.com/fhir"); + Bundle bundle = client.search().forResource(MyPatientWithExtensions.class).returnBundle(Bundle.class).execute(); + + assertEquals(1, bundle.getEntry().size()); + assertEquals(MyPatientWithExtensions.class, bundle.getEntry().get(0).getResource().getClass()); + } + + @Test + public void testValidateCustomTypeFromClientRead() throws Exception { + IParser p = ourCtx.newXmlParser(); + + MyPatientWithExtensions patient = new MyPatientWithExtensions(); + patient.setId("123"); + patient.getText().setDivAsString("OK!"); + + final String respString = p.encodeResourceToString(patient); + ArgumentCaptor capt = ArgumentCaptor.forClass(HttpUriRequest.class); + when(myHttpClient.execute(capt.capture())).thenReturn(myHttpResponse); + 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() { + @Override + public ReaderInputStream answer(InvocationOnMock theInvocation) throws Throwable { + return new ReaderInputStream(new StringReader(respString), Charset.forName("UTF-8")); + } + }); + + IGenericClient client = ourCtx.newRestfulGenericClient("http://example.com/fhir"); + MyPatientWithExtensions read = client.read().resource(MyPatientWithExtensions.class).withId(new IdType("1")).execute(); + assertEquals("
OK!
", read.getText().getDivAsString()); + } + private byte[] extractBodyAsByteArray(ArgumentCaptor capt) throws IOException { byte[] body = IOUtils.toByteArray(((HttpEntityEnclosingRequestBase) capt.getAllValues().get(0)).getEntity().getContent()); return body; diff --git a/hapi-fhir-structures-dstu3/src/test/java/ca/uhn/fhir/rest/client/NonGenericClientDstu3Test.java b/hapi-fhir-structures-dstu3/src/test/java/ca/uhn/fhir/rest/client/NonGenericClientDstu3Test.java index 11b780fb1b9..0ec25df39d7 100644 --- a/hapi-fhir-structures-dstu3/src/test/java/ca/uhn/fhir/rest/client/NonGenericClientDstu3Test.java +++ b/hapi-fhir-structures-dstu3/src/test/java/ca/uhn/fhir/rest/client/NonGenericClientDstu3Test.java @@ -7,6 +7,7 @@ import static org.mockito.Mockito.when; import java.io.IOException; import java.io.StringReader; import java.nio.charset.Charset; +import java.util.List; import org.apache.commons.io.IOUtils; import org.apache.commons.io.input.ReaderInputStream; @@ -17,6 +18,8 @@ import org.apache.http.client.methods.HttpEntityEnclosingRequestBase; import org.apache.http.client.methods.HttpUriRequest; import org.apache.http.message.BasicHeader; import org.apache.http.message.BasicStatusLine; +import org.hl7.fhir.dstu3.model.Bundle; +import org.hl7.fhir.dstu3.model.IdType; import org.hl7.fhir.dstu3.model.OperationOutcome; import org.hl7.fhir.dstu3.model.Patient; import org.hl7.fhir.instance.model.api.IBaseResource; @@ -31,8 +34,7 @@ import org.mockito.stubbing.Answer; import ca.uhn.fhir.context.FhirContext; import ca.uhn.fhir.parser.IParser; -import ca.uhn.fhir.rest.annotation.ResourceParam; -import ca.uhn.fhir.rest.annotation.Validate; +import ca.uhn.fhir.rest.annotation.*; import ca.uhn.fhir.rest.api.MethodOutcome; import ca.uhn.fhir.rest.api.ValidationModeEnum; import ca.uhn.fhir.rest.client.api.IRestfulClient; @@ -60,6 +62,62 @@ public class NonGenericClientDstu3Test { return body; } + @Test + public void testValidateCustomTypeFromClientSearch() throws Exception { + IParser p = ourCtx.newXmlParser(); + + Bundle b = new Bundle(); + + MyPatientWithExtensions patient = new MyPatientWithExtensions(); + patient.setId("123"); + patient.getText().setDivAsString("OK!"); + b.addEntry().setResource(patient); + + + final String respString = p.encodeResourceToString(b); + ArgumentCaptor capt = ArgumentCaptor.forClass(HttpUriRequest.class); + when(myHttpClient.execute(capt.capture())).thenReturn(myHttpResponse); + 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() { + @Override + public ReaderInputStream answer(InvocationOnMock theInvocation) throws Throwable { + return new ReaderInputStream(new StringReader(respString), Charset.forName("UTF-8")); + } + }); + + IClientWithCustomType client = ourCtx.newRestfulClient(IClientWithCustomType.class, "http://example.com/fhir"); + List list = client.search(); + + assertEquals(1, list.size()); + assertEquals(MyPatientWithExtensions.class, list.get(0).getClass()); + } + + @Test + public void testValidateCustomTypeFromClientRead() throws Exception { + IParser p = ourCtx.newXmlParser(); + + MyPatientWithExtensions patient = new MyPatientWithExtensions(); + patient.setId("123"); + patient.getText().setDivAsString("OK!"); + + final String respString = p.encodeResourceToString(patient); + ArgumentCaptor capt = ArgumentCaptor.forClass(HttpUriRequest.class); + when(myHttpClient.execute(capt.capture())).thenReturn(myHttpResponse); + 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() { + @Override + public ReaderInputStream answer(InvocationOnMock theInvocation) throws Throwable { + return new ReaderInputStream(new StringReader(respString), Charset.forName("UTF-8")); + } + }); + + IClientWithCustomType client = ourCtx.newRestfulClient(IClientWithCustomType.class, "http://example.com/fhir"); + MyPatientWithExtensions read = client.read(new IdType("1")); + assertEquals("
OK!
", read.getText().getDivAsString()); + } + @Test public void testValidateResourceOnly() throws Exception { IParser p = ourCtx.newXmlParser(); @@ -102,21 +160,31 @@ public class NonGenericClientDstu3Test { } + @AfterClass + public static void afterClassClearContext() { + TestUtil.clearAllStaticFieldsForUnitTest(); + } + + @BeforeClass + public static void beforeClass() { + ourCtx = FhirContext.forDstu3(); + } + private interface IClient extends IRestfulClient { @Validate MethodOutcome validate(@ResourceParam IBaseResource theResource, @Validate.Mode ValidationModeEnum theMode, @Validate.Profile String theProfile); } - - @AfterClass - public static void afterClassClearContext() { - TestUtil.clearAllStaticFieldsForUnitTest(); - } - @BeforeClass - public static void beforeClass() { - ourCtx = FhirContext.forDstu3(); + private interface IClientWithCustomType extends IRestfulClient { + + @Search + List search(); + + @Read + MyPatientWithExtensions read(@IdParam IdType theId); + } } diff --git a/src/changes/changes.xml b/src/changes/changes.xml index cc81ef6ac23..3e2fdcdc29c 100644 --- a/src/changes/changes.xml +++ b/src/changes/changes.xml @@ -123,6 +123,10 @@ conditional deletes which did not find any matches, per FHIR-I decision. + + Client that declares explicitly that it is searching/reading/etc for + a custom type did not automatically parse into that type. +