Fix #315 - Use custom types for searches and other client operations
when requested
This commit is contained in:
parent
1adfc4b4d9
commit
c6f06548fc
|
@ -3,14 +3,17 @@ package example;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.hl7.fhir.dstu3.model.Bundle;
|
||||||
import org.hl7.fhir.dstu3.model.DateTimeType;
|
import org.hl7.fhir.dstu3.model.DateTimeType;
|
||||||
import org.hl7.fhir.dstu3.model.Extension;
|
import org.hl7.fhir.dstu3.model.Extension;
|
||||||
import org.hl7.fhir.dstu3.model.HumanName;
|
import org.hl7.fhir.dstu3.model.HumanName;
|
||||||
|
import org.hl7.fhir.dstu3.model.IdType;
|
||||||
import org.hl7.fhir.dstu3.model.Identifier.IdentifierUse;
|
import org.hl7.fhir.dstu3.model.Identifier.IdentifierUse;
|
||||||
import org.hl7.fhir.dstu3.model.Patient;
|
import org.hl7.fhir.dstu3.model.Patient;
|
||||||
import org.hl7.fhir.dstu3.model.StringType;
|
import org.hl7.fhir.dstu3.model.StringType;
|
||||||
|
|
||||||
import ca.uhn.fhir.context.FhirContext;
|
import ca.uhn.fhir.context.FhirContext;
|
||||||
|
import ca.uhn.fhir.parser.CustomTypeDstu3Test.MyCustomPatient;
|
||||||
import ca.uhn.fhir.parser.DataFormatException;
|
import ca.uhn.fhir.parser.DataFormatException;
|
||||||
import ca.uhn.fhir.rest.client.IGenericClient;
|
import ca.uhn.fhir.rest.client.IGenericClient;
|
||||||
|
|
||||||
|
@ -33,6 +36,30 @@ client.create().resource(custPatient).execute();
|
||||||
custPatient = client.read().resource(MyPatient.class).withId("123").execute();
|
custPatient = client.read().resource(MyPatient.class).withId("123").execute();
|
||||||
//END SNIPPET: customTypeClientSimple
|
//END SNIPPET: customTypeClientSimple
|
||||||
|
|
||||||
|
//START SNIPPET: customTypeClientSearch
|
||||||
|
// Perform the search using the custom type
|
||||||
|
Bundle bundle = client
|
||||||
|
.search()
|
||||||
|
.forResource(MyPatient.class)
|
||||||
|
.returnBundle(Bundle.class)
|
||||||
|
.execute();
|
||||||
|
|
||||||
|
// Entries in the return bundle will use the given type
|
||||||
|
MyPatient pat0 = (MyPatient) bundle.getEntry().get(0).getResource();
|
||||||
|
//END SNIPPET: customTypeClientSearch
|
||||||
|
|
||||||
|
//START SNIPPET: customTypeClientSearch2
|
||||||
|
//Perform the search using the custom type
|
||||||
|
bundle = client
|
||||||
|
.history()
|
||||||
|
.onInstance(new IdType("Patient/123"))
|
||||||
|
.andReturnBundle(Bundle.class)
|
||||||
|
.preferResponseType(MyPatient.class)
|
||||||
|
.execute();
|
||||||
|
|
||||||
|
//Entries in the return bundle will use the given type
|
||||||
|
MyPatient historyPatient0 = (MyPatient) bundle.getEntry().get(0).getResource();
|
||||||
|
//END SNIPPET: customTypeClientSearch2
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -88,6 +88,7 @@ public abstract class BaseParser implements IParser {
|
||||||
private IIdType myEncodeForceResourceId;
|
private IIdType myEncodeForceResourceId;
|
||||||
private IParserErrorHandler myErrorHandler;
|
private IParserErrorHandler myErrorHandler;
|
||||||
private boolean myOmitResourceId;
|
private boolean myOmitResourceId;
|
||||||
|
private List<Class<? extends IBaseResource>> myPreferTypes;
|
||||||
private String myServerBaseUrl;
|
private String myServerBaseUrl;
|
||||||
private boolean myStripVersionsFromReferences = true;
|
private boolean myStripVersionsFromReferences = true;
|
||||||
private boolean mySummaryMode;
|
private boolean mySummaryMode;
|
||||||
|
@ -437,6 +438,11 @@ public abstract class BaseParser implements IParser {
|
||||||
return tags;
|
return tags;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<Class<? extends IBaseResource>> getPreferTypes() {
|
||||||
|
return myPreferTypes;
|
||||||
|
}
|
||||||
|
|
||||||
@SuppressWarnings("deprecation")
|
@SuppressWarnings("deprecation")
|
||||||
protected <T extends IPrimitiveType<String>> List<T> getProfileTagsForEncoding(IBaseResource theResource, List<T> theProfiles) {
|
protected <T extends IPrimitiveType<String>> List<T> getProfileTagsForEncoding(IBaseResource theResource, List<T> theProfiles) {
|
||||||
switch (myContext.getAddProfileTagWhenEncoding()) {
|
switch (myContext.getAddProfileTagWhenEncoding()) {
|
||||||
|
@ -717,6 +723,11 @@ public abstract class BaseParser implements IParser {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setPreferTypes(List<Class<? extends IBaseResource>> thePreferTypes) {
|
||||||
|
myPreferTypes = thePreferTypes;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public IParser setServerBaseUrl(String theUrl) {
|
public IParser setServerBaseUrl(String theUrl) {
|
||||||
myServerBaseUrl = isNotBlank(theUrl) ? theUrl : null;
|
myServerBaseUrl = isNotBlank(theUrl) ? theUrl : null;
|
||||||
|
|
|
@ -23,6 +23,7 @@ package ca.uhn.fhir.parser;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.Reader;
|
import java.io.Reader;
|
||||||
import java.io.Writer;
|
import java.io.Writer;
|
||||||
|
import java.util.List;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
import org.hl7.fhir.instance.model.api.IAnyResource;
|
import org.hl7.fhir.instance.model.api.IAnyResource;
|
||||||
|
@ -30,6 +31,7 @@ import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||||
import org.hl7.fhir.instance.model.api.IIdType;
|
import org.hl7.fhir.instance.model.api.IIdType;
|
||||||
|
|
||||||
import ca.uhn.fhir.context.ConfigurationException;
|
import ca.uhn.fhir.context.ConfigurationException;
|
||||||
|
import ca.uhn.fhir.context.FhirContext;
|
||||||
import ca.uhn.fhir.model.api.Bundle;
|
import ca.uhn.fhir.model.api.Bundle;
|
||||||
import ca.uhn.fhir.model.api.IResource;
|
import ca.uhn.fhir.model.api.IResource;
|
||||||
import ca.uhn.fhir.model.api.TagList;
|
import ca.uhn.fhir.model.api.TagList;
|
||||||
|
@ -95,6 +97,14 @@ public interface IParser {
|
||||||
*/
|
*/
|
||||||
EncodingEnum getEncoding();
|
EncodingEnum getEncoding();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the preferred types, as set using {@link #setPreferTypes(List)}
|
||||||
|
*
|
||||||
|
* @return Returns the preferred types, or <code>null</code>
|
||||||
|
* @see #setPreferTypes(List)
|
||||||
|
*/
|
||||||
|
List<Class<? extends IBaseResource>> getPreferTypes();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns true if resource IDs should be omitted
|
* Returns true if resource IDs should be omitted
|
||||||
*
|
*
|
||||||
|
@ -289,6 +299,25 @@ public interface IParser {
|
||||||
*/
|
*/
|
||||||
IParser setParserErrorHandler(IParserErrorHandler theErrorHandler);
|
IParser setParserErrorHandler(IParserErrorHandler theErrorHandler);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If set, when parsing resources the parser will try to use the given types when possible, in
|
||||||
|
* the order that they are provided (from highest to lowest priority). For example, if a custom
|
||||||
|
* type which declares to implement the Patient resource is passed in here, and the
|
||||||
|
* parser is parsing a Bundle containing a Patient resource, the parser will use the given
|
||||||
|
* custom type.
|
||||||
|
* <p>
|
||||||
|
* This feature is related to, but not the same as the
|
||||||
|
* {@link FhirContext#setDefaultTypeForProfile(String, Class)} feature.
|
||||||
|
* <code>setDefaultTypeForProfile</code> is used to specify a type to be used
|
||||||
|
* when a resource explicitly declares support for a given profile. This
|
||||||
|
* feature specifies a type to be used irrespective of the profile declaration
|
||||||
|
* in the metadata statement.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @param thePreferTypes The preferred types, or <code>null</code>
|
||||||
|
*/
|
||||||
|
void setPreferTypes(List<Class<? extends IBaseResource>> thePreferTypes);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the "pretty print" flag, meaning that the parser will encode resources with human-readable spacing and
|
* Sets the "pretty print" flag, meaning that the parser will encode resources with human-readable spacing and
|
||||||
* newlines between elements instead of condensing output as much as possible.
|
* newlines between elements instead of condensing output as much as possible.
|
||||||
|
|
|
@ -220,7 +220,7 @@ public class JsonParser extends BaseParser implements IParser {
|
||||||
assertObjectOfType(resourceTypeObj, JsonValue.ValueType.STRING, "resourceType");
|
assertObjectOfType(resourceTypeObj, JsonValue.ValueType.STRING, "resourceType");
|
||||||
String resourceType = ((JsonString) resourceTypeObj).getString();
|
String resourceType = ((JsonString) resourceTypeObj).getString();
|
||||||
|
|
||||||
ParserState<? extends IBaseResource> state = ParserState.getPreResourceInstance(theResourceType, myContext, true, getErrorHandler());
|
ParserState<? extends IBaseResource> state = ParserState.getPreResourceInstance(this, theResourceType, myContext, true, getErrorHandler());
|
||||||
state.enteringNewElement(null, resourceType);
|
state.enteringNewElement(null, resourceType);
|
||||||
|
|
||||||
parseChildren(object, state);
|
parseChildren(object, state);
|
||||||
|
@ -1097,7 +1097,7 @@ public class JsonParser extends BaseParser implements IParser {
|
||||||
throw new DataFormatException("Trying to parse bundle but found resourceType other than 'Bundle'. Found: '" + resourceType + "'");
|
throw new DataFormatException("Trying to parse bundle but found resourceType other than 'Bundle'. Found: '" + resourceType + "'");
|
||||||
}
|
}
|
||||||
|
|
||||||
ParserState<Bundle> state = ParserState.getPreAtomInstance(myContext, theResourceType, true, getErrorHandler());
|
ParserState<Bundle> state = ParserState.getPreAtomInstance(this, myContext, theResourceType, true, getErrorHandler());
|
||||||
if (myContext.getVersion().getVersion().isNewerThan(FhirVersionEnum.DSTU1)) {
|
if (myContext.getVersion().getVersion().isNewerThan(FhirVersionEnum.DSTU1)) {
|
||||||
state.enteringNewElement(null, "Bundle");
|
state.enteringNewElement(null, "Bundle");
|
||||||
} else {
|
} else {
|
||||||
|
@ -1420,7 +1420,7 @@ public class JsonParser extends BaseParser implements IParser {
|
||||||
assertObjectOfType(resourceTypeObj, JsonValue.ValueType.STRING, "resourceType");
|
assertObjectOfType(resourceTypeObj, JsonValue.ValueType.STRING, "resourceType");
|
||||||
String resourceType = ((JsonString) resourceTypeObj).getString();
|
String resourceType = ((JsonString) resourceTypeObj).getString();
|
||||||
|
|
||||||
ParserState<TagList> state = ParserState.getPreTagListInstance(myContext, true, getErrorHandler());
|
ParserState<TagList> state = ParserState.getPreTagListInstance(this, myContext, true, getErrorHandler());
|
||||||
state.enteringNewElement(null, resourceType);
|
state.enteringNewElement(null, resourceType);
|
||||||
|
|
||||||
parseChildren(object, state);
|
parseChildren(object, state);
|
||||||
|
|
|
@ -91,14 +91,16 @@ class ParserState<T> {
|
||||||
|
|
||||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(ParserState.class);
|
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(ParserState.class);
|
||||||
private List<String> myComments = new ArrayList<String>(2);
|
private List<String> myComments = new ArrayList<String>(2);
|
||||||
private FhirContext myContext;
|
private final FhirContext myContext;
|
||||||
private IParserErrorHandler myErrorHandler;
|
private final IParserErrorHandler myErrorHandler;
|
||||||
private boolean myJsonMode;
|
private final boolean myJsonMode;
|
||||||
private T myObject;
|
private T myObject;
|
||||||
private BaseState myState;
|
private BaseState myState;
|
||||||
private IBase myPreviousElement;
|
private IBase myPreviousElement;
|
||||||
|
private final IParser myParser;
|
||||||
|
|
||||||
private ParserState(FhirContext theContext, boolean theJsonMode, IParserErrorHandler theErrorHandler) {
|
private ParserState(IParser theParser, FhirContext theContext, boolean theJsonMode, IParserErrorHandler theErrorHandler) {
|
||||||
|
myParser = theParser;
|
||||||
myContext = theContext;
|
myContext = theContext;
|
||||||
myJsonMode = theJsonMode;
|
myJsonMode = theJsonMode;
|
||||||
myErrorHandler = theErrorHandler;
|
myErrorHandler = theErrorHandler;
|
||||||
|
@ -247,8 +249,8 @@ class ParserState<T> {
|
||||||
myState.xmlEvent(theNextEvent);
|
myState.xmlEvent(theNextEvent);
|
||||||
}
|
}
|
||||||
|
|
||||||
static ParserState<Bundle> getPreAtomInstance(FhirContext theContext, Class<? extends IBaseResource> theResourceType, boolean theJsonMode, IParserErrorHandler theErrorHandler) throws DataFormatException {
|
static ParserState<Bundle> getPreAtomInstance(IParser theParser, FhirContext theContext, Class<? extends IBaseResource> theResourceType, boolean theJsonMode, IParserErrorHandler theErrorHandler) throws DataFormatException {
|
||||||
ParserState<Bundle> retVal = new ParserState<Bundle>(theContext, theJsonMode, theErrorHandler);
|
ParserState<Bundle> retVal = new ParserState<Bundle>(theParser, theContext, theJsonMode, theErrorHandler);
|
||||||
if (theContext.getVersion().getVersion() == FhirVersionEnum.DSTU1) {
|
if (theContext.getVersion().getVersion() == FhirVersionEnum.DSTU1) {
|
||||||
retVal.push(retVal.new PreAtomState(theResourceType));
|
retVal.push(retVal.new PreAtomState(theResourceType));
|
||||||
} else {
|
} else {
|
||||||
|
@ -261,8 +263,8 @@ class ParserState<T> {
|
||||||
* @param theResourceType
|
* @param theResourceType
|
||||||
* May be null
|
* May be null
|
||||||
*/
|
*/
|
||||||
static <T extends IBaseResource> ParserState<T> getPreResourceInstance(Class<T> theResourceType, FhirContext theContext, boolean theJsonMode, IParserErrorHandler theErrorHandler) throws DataFormatException {
|
static <T extends IBaseResource> ParserState<T> getPreResourceInstance(IParser theParser, Class<T> theResourceType, FhirContext theContext, boolean theJsonMode, IParserErrorHandler theErrorHandler) throws DataFormatException {
|
||||||
ParserState<T> retVal = new ParserState<T>(theContext, theJsonMode, theErrorHandler);
|
ParserState<T> retVal = new ParserState<T>(theParser, theContext, theJsonMode, theErrorHandler);
|
||||||
if (theResourceType == null) {
|
if (theResourceType == null) {
|
||||||
if (theContext.getVersion().getVersion().isRi()) {
|
if (theContext.getVersion().getVersion().isRi()) {
|
||||||
retVal.push(retVal.new PreResourceStateHl7Org(theResourceType));
|
retVal.push(retVal.new PreResourceStateHl7Org(theResourceType));
|
||||||
|
@ -279,8 +281,8 @@ class ParserState<T> {
|
||||||
return retVal;
|
return retVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
static ParserState<TagList> getPreTagListInstance(FhirContext theContext, boolean theJsonMode, IParserErrorHandler theErrorHandler) {
|
static ParserState<TagList> getPreTagListInstance(IParser theParser, FhirContext theContext, boolean theJsonMode, IParserErrorHandler theErrorHandler) {
|
||||||
ParserState<TagList> retVal = new ParserState<TagList>(theContext, theJsonMode, theErrorHandler);
|
ParserState<TagList> retVal = new ParserState<TagList>(theParser, theContext, theJsonMode, theErrorHandler);
|
||||||
retVal.push(retVal.new PreTagListState());
|
retVal.push(retVal.new PreTagListState());
|
||||||
return retVal;
|
return retVal;
|
||||||
}
|
}
|
||||||
|
@ -1997,7 +1999,18 @@ class ParserState<T> {
|
||||||
public void enteringNewElement(String theNamespaceUri, String theLocalPart) throws DataFormatException {
|
public void enteringNewElement(String theNamespaceUri, String theLocalPart) throws DataFormatException {
|
||||||
BaseRuntimeElementDefinition<?> definition;
|
BaseRuntimeElementDefinition<?> definition;
|
||||||
if (myResourceType == null) {
|
if (myResourceType == null) {
|
||||||
|
definition = null;
|
||||||
|
if (myParser.getPreferTypes() != null) {
|
||||||
|
for (Class<? extends IBaseResource> next : myParser.getPreferTypes()) {
|
||||||
|
RuntimeResourceDefinition nextDef = myContext.getResourceDefinition(next);
|
||||||
|
if (nextDef.getName().equals(theLocalPart)) {
|
||||||
|
definition = nextDef;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (definition == null) {
|
||||||
definition = myContext.getResourceDefinition(myParentVersion, theLocalPart);
|
definition = myContext.getResourceDefinition(myParentVersion, theLocalPart);
|
||||||
|
}
|
||||||
if ((definition == null)) {
|
if ((definition == null)) {
|
||||||
throw new DataFormatException("Element '" + theLocalPart + "' is not a known resource type, expected a resource at this position");
|
throw new DataFormatException("Element '" + theLocalPart + "' is not a known resource type, expected a resource at this position");
|
||||||
}
|
}
|
||||||
|
|
|
@ -1080,12 +1080,12 @@ public class XmlParser extends BaseParser implements IParser {
|
||||||
}
|
}
|
||||||
|
|
||||||
private Bundle parseBundle(XMLEventReader theStreamReader, Class<? extends IBaseResource> theResourceType) {
|
private Bundle parseBundle(XMLEventReader theStreamReader, Class<? extends IBaseResource> theResourceType) {
|
||||||
ParserState<Bundle> parserState = ParserState.getPreAtomInstance(myContext, theResourceType, false, getErrorHandler());
|
ParserState<Bundle> parserState = ParserState.getPreAtomInstance(this, myContext, theResourceType, false, getErrorHandler());
|
||||||
return doXmlLoop(theStreamReader, parserState);
|
return doXmlLoop(theStreamReader, parserState);
|
||||||
}
|
}
|
||||||
|
|
||||||
private <T extends IBaseResource> T parseResource(Class<T> theResourceType, XMLEventReader theStreamReader) {
|
private <T extends IBaseResource> T parseResource(Class<T> theResourceType, XMLEventReader theStreamReader) {
|
||||||
ParserState<T> parserState = ParserState.getPreResourceInstance(theResourceType, myContext, false, getErrorHandler());
|
ParserState<T> parserState = ParserState.getPreResourceInstance(this, theResourceType, myContext, false, getErrorHandler());
|
||||||
return doXmlLoop(theStreamReader, parserState);
|
return doXmlLoop(theStreamReader, parserState);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1093,7 +1093,7 @@ public class XmlParser extends BaseParser implements IParser {
|
||||||
public TagList parseTagList(Reader theReader) {
|
public TagList parseTagList(Reader theReader) {
|
||||||
XMLEventReader streamReader = createStreamReader(theReader);
|
XMLEventReader streamReader = createStreamReader(theReader);
|
||||||
|
|
||||||
ParserState<TagList> parserState = ParserState.getPreTagListInstance(myContext, false, getErrorHandler());
|
ParserState<TagList> parserState = ParserState.getPreTagListInstance(this, myContext, false, getErrorHandler());
|
||||||
return doXmlLoop(streamReader, parserState);
|
return doXmlLoop(streamReader, parserState);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -107,6 +107,13 @@ public abstract class BaseClient implements IRestfulClient {
|
||||||
return retVal;
|
return retVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public <T extends IBaseResource> T fetchResourceFromUrl(Class<T> theResourceType, String theUrl) {
|
||||||
|
BaseHttpClientInvocation clientInvocation = new HttpGetClientInvocation(getFhirContext(), theUrl);
|
||||||
|
ResourceResponseHandler<T> binding = new ResourceResponseHandler<T>(theResourceType);
|
||||||
|
return invokeClient(getFhirContext(), binding, clientInvocation, null, false, false, null, null);
|
||||||
|
}
|
||||||
|
|
||||||
void forceConformanceCheck() {
|
void forceConformanceCheck() {
|
||||||
myFactory.validateServerBase(myUrlBase, myClient, this);
|
myFactory.validateServerBase(myUrlBase, myClient, this);
|
||||||
}
|
}
|
||||||
|
@ -221,7 +228,7 @@ public abstract class BaseClient implements IRestfulClient {
|
||||||
if (theLogRequestAndResponse) {
|
if (theLogRequestAndResponse) {
|
||||||
ourLog.info("Client invoking: {}", httpRequest);
|
ourLog.info("Client invoking: {}", httpRequest);
|
||||||
String body = httpRequest.getRequestBodyFromStream();
|
String body = httpRequest.getRequestBodyFromStream();
|
||||||
if(body != null) {
|
if (body != null) {
|
||||||
ourLog.info("Client request body: {}", body);
|
ourLog.info("Client request body: {}", body);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -337,7 +344,7 @@ public abstract class BaseClient implements IRestfulClient {
|
||||||
throw new FhirClientConnectionException(e);
|
throw new FhirClientConnectionException(e);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
throw new FhirClientConnectionException(e);
|
throw new FhirClientConnectionException(e);
|
||||||
} catch(RuntimeException e) {
|
} catch (RuntimeException e) {
|
||||||
throw e;
|
throw e;
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
throw new FhirClientConnectionException(e);
|
throw new FhirClientConnectionException(e);
|
||||||
|
@ -449,28 +456,47 @@ public abstract class BaseClient implements IRestfulClient {
|
||||||
Validate.notNull(theInterceptor, "Interceptor can not be null");
|
Validate.notNull(theInterceptor, "Interceptor can not be null");
|
||||||
myInterceptors.remove(theInterceptor);
|
myInterceptors.remove(theInterceptor);
|
||||||
}
|
}
|
||||||
|
static ArrayList<Class<? extends IBaseResource>> toTypeList(Class<? extends IBaseResource> thePreferResponseType) {
|
||||||
@Override
|
ArrayList<Class<? extends IBaseResource>> preferResponseTypes = null;
|
||||||
public <T extends IBaseResource> T fetchResourceFromUrl(Class<T> theResourceType, String theUrl) {
|
if (thePreferResponseType != null) {
|
||||||
BaseHttpClientInvocation clientInvocation = new HttpGetClientInvocation(getFhirContext(), theUrl);
|
preferResponseTypes = new ArrayList<Class<? extends IBaseResource>>(1);
|
||||||
ResourceResponseHandler<T> binding = new ResourceResponseHandler<T>(theResourceType, null, false);
|
preferResponseTypes.add(thePreferResponseType);
|
||||||
return invokeClient(getFhirContext(), binding, clientInvocation, null, false, false, null, null);
|
}
|
||||||
|
return preferResponseTypes;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected final class ResourceResponseHandler<T extends IBaseResource> implements IClientResponseHandler<T> {
|
protected final class ResourceResponseHandler<T extends IBaseResource> implements IClientResponseHandler<T> {
|
||||||
|
|
||||||
private boolean myAllowHtmlResponse;
|
private boolean myAllowHtmlResponse;
|
||||||
private IIdType myId;
|
private IIdType myId;
|
||||||
private Class<T> myType;
|
private List<Class<? extends IBaseResource>> myPreferResponseTypes;
|
||||||
|
private Class<T> myReturnType;
|
||||||
|
|
||||||
public ResourceResponseHandler(Class<T> theType, IIdType theId) {
|
public ResourceResponseHandler() {
|
||||||
myType = theType;
|
this(null);
|
||||||
myId = theId;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public ResourceResponseHandler(Class<T> theType, IIdType theId, boolean theAllowHtmlResponse) {
|
public ResourceResponseHandler(Class<T> theReturnType) {
|
||||||
myType = theType;
|
this(theReturnType, null, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ResourceResponseHandler(Class<T> theReturnType, Class<? extends IBaseResource> thePreferResponseType, IIdType theId) {
|
||||||
|
this(theReturnType, thePreferResponseType, theId, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ResourceResponseHandler(Class<T> theReturnType, Class<? extends IBaseResource> thePreferResponseType, IIdType theId, boolean theAllowHtmlResponse) {
|
||||||
|
this(theReturnType, toTypeList(thePreferResponseType), theId, theAllowHtmlResponse);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ResourceResponseHandler(Class<T> theClass, List<Class<? extends IBaseResource>> thePreferResponseTypes) {
|
||||||
|
this(theClass, thePreferResponseTypes, null, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public ResourceResponseHandler(Class<T> theReturnType, List<Class<? extends IBaseResource>> thePreferResponseTypes, IIdType theId, boolean theAllowHtmlResponse) {
|
||||||
|
myReturnType = theReturnType;
|
||||||
myId = theId;
|
myId = theId;
|
||||||
|
myPreferResponseTypes = thePreferResponseTypes;
|
||||||
myAllowHtmlResponse = theAllowHtmlResponse;
|
myAllowHtmlResponse = theAllowHtmlResponse;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -478,13 +504,16 @@ public abstract class BaseClient implements IRestfulClient {
|
||||||
public T invokeClient(String theResponseMimeType, Reader theResponseReader, int theResponseStatusCode, Map<String, List<String>> theHeaders) throws BaseServerResponseException {
|
public T invokeClient(String theResponseMimeType, Reader theResponseReader, int theResponseStatusCode, Map<String, List<String>> theHeaders) throws BaseServerResponseException {
|
||||||
EncodingEnum respType = EncodingEnum.forContentType(theResponseMimeType);
|
EncodingEnum respType = EncodingEnum.forContentType(theResponseMimeType);
|
||||||
if (respType == null) {
|
if (respType == null) {
|
||||||
if (myAllowHtmlResponse && theResponseMimeType.toLowerCase().contains(Constants.CT_HTML) && myType != null) {
|
if (myAllowHtmlResponse && theResponseMimeType.toLowerCase().contains(Constants.CT_HTML) && myReturnType != null) {
|
||||||
return readHtmlResponse(theResponseReader);
|
return readHtmlResponse(theResponseReader);
|
||||||
}
|
}
|
||||||
throw NonFhirResponseException.newInstance(theResponseStatusCode, theResponseMimeType, theResponseReader);
|
throw NonFhirResponseException.newInstance(theResponseStatusCode, theResponseMimeType, theResponseReader);
|
||||||
}
|
}
|
||||||
IParser parser = respType.newParser(getFhirContext());
|
IParser parser = respType.newParser(getFhirContext());
|
||||||
T retVal = parser.parseResource(myType, theResponseReader);
|
if (myPreferResponseTypes != null) {
|
||||||
|
parser.setPreferTypes(myPreferResponseTypes);
|
||||||
|
}
|
||||||
|
T retVal = parser.parseResource(myReturnType, theResponseReader);
|
||||||
|
|
||||||
MethodUtil.parseClientRequestResourceHeaders(myId, theHeaders, retVal);
|
MethodUtil.parseClientRequestResourceHeaders(myId, theHeaders, retVal);
|
||||||
|
|
||||||
|
@ -493,7 +522,7 @@ public abstract class BaseClient implements IRestfulClient {
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
private T readHtmlResponse(Reader theResponseReader) {
|
private T readHtmlResponse(Reader theResponseReader) {
|
||||||
RuntimeResourceDefinition resDef = getFhirContext().getResourceDefinition(myType);
|
RuntimeResourceDefinition resDef = getFhirContext().getResourceDefinition(myReturnType);
|
||||||
IBaseResource instance = resDef.newInstance();
|
IBaseResource instance = resDef.newInstance();
|
||||||
BaseRuntimeChildDefinition textChild = resDef.getChildByName("text");
|
BaseRuntimeChildDefinition textChild = resDef.getChildByName("text");
|
||||||
BaseRuntimeElementCompositeDefinition<?> textElement = (BaseRuntimeElementCompositeDefinition<?>) textChild.getChildByName("text");
|
BaseRuntimeElementCompositeDefinition<?> textElement = (BaseRuntimeElementCompositeDefinition<?>) textChild.getChildByName("text");
|
||||||
|
@ -511,6 +540,10 @@ public abstract class BaseClient implements IRestfulClient {
|
||||||
divChild.getMutator().addValue(textInstance, divInstance);
|
divChild.getMutator().addValue(textInstance, divInstance);
|
||||||
return (T) instance;
|
return (T) instance;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setPreferResponseTypes(List<Class<? extends IBaseResource>> thePreferResponseTypes) {
|
||||||
|
myPreferResponseTypes = thePreferResponseTypes;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -182,7 +182,7 @@ public class GenericClient extends BaseClient implements IGenericClient {
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
Class<BaseConformance> conformance = (Class<BaseConformance>) myContext.getResourceDefinition("Conformance").getImplementingClass();
|
Class<BaseConformance> conformance = (Class<BaseConformance>) myContext.getResourceDefinition("Conformance").getImplementingClass();
|
||||||
|
|
||||||
ResourceResponseHandler<? extends BaseConformance> binding = new ResourceResponseHandler<BaseConformance>(conformance, null);
|
ResourceResponseHandler<? extends BaseConformance> binding = new ResourceResponseHandler<BaseConformance>(conformance);
|
||||||
BaseConformance resp = invokeClient(myContext, binding, invocation, myLogRequestAndResponse);
|
BaseConformance resp = invokeClient(myContext, binding, invocation, myLogRequestAndResponse);
|
||||||
return resp;
|
return resp;
|
||||||
}
|
}
|
||||||
|
@ -263,7 +263,7 @@ public class GenericClient extends BaseClient implements IGenericClient {
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean allowHtmlResponse = (theSummary == SummaryEnum.TEXT) || (theSummary == null && getSummary() == SummaryEnum.TEXT);
|
boolean allowHtmlResponse = (theSummary == SummaryEnum.TEXT) || (theSummary == null && getSummary() == SummaryEnum.TEXT);
|
||||||
ResourceResponseHandler<T> binding = new ResourceResponseHandler<T>(theType, id, allowHtmlResponse);
|
ResourceResponseHandler<T> binding = new ResourceResponseHandler<T>(theType, (Class<? extends IBaseResource>)null, id, allowHtmlResponse);
|
||||||
|
|
||||||
if (theNotModifiedHandler == null) {
|
if (theNotModifiedHandler == null) {
|
||||||
return invokeClient(myContext, binding, invocation, theEncoding, thePrettyPrint, myLogRequestAndResponse, theSummary, theSubsetElements);
|
return invokeClient(myContext, binding, invocation, theEncoding, thePrettyPrint, myLogRequestAndResponse, theSummary, theSubsetElements);
|
||||||
|
@ -596,6 +596,39 @@ public class GenericClient extends BaseClient implements IGenericClient {
|
||||||
}
|
}
|
||||||
|
|
||||||
private abstract class BaseClientExecutable<T extends IClientExecutable<?, ?>, Y> implements IClientExecutable<T, Y> {
|
private abstract class BaseClientExecutable<T extends IClientExecutable<?, ?>, Y> implements IClientExecutable<T, Y> {
|
||||||
|
|
||||||
|
private List<Class<? extends IBaseResource>> myPreferResponseTypes;
|
||||||
|
|
||||||
|
public List<Class<? extends IBaseResource>> getPreferResponseTypes() {
|
||||||
|
return myPreferResponseTypes;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<Class<? extends IBaseResource>> getPreferResponseTypes(Class<? extends IBaseResource> theDefault) {
|
||||||
|
if (myPreferResponseTypes != null) {
|
||||||
|
return myPreferResponseTypes;
|
||||||
|
} else {
|
||||||
|
return toTypeList(theDefault);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
@Override
|
||||||
|
public T preferResponseType(Class<? extends IBaseResource> theClass) {
|
||||||
|
myPreferResponseTypes = null;
|
||||||
|
if (theClass != null) {
|
||||||
|
myPreferResponseTypes = new ArrayList<Class<? extends IBaseResource>>();
|
||||||
|
myPreferResponseTypes.add(theClass);
|
||||||
|
}
|
||||||
|
return (T) this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
@Override
|
||||||
|
public T preferResponseTypes(List<Class<? extends IBaseResource>> theClass) {
|
||||||
|
myPreferResponseTypes = theClass;
|
||||||
|
return (T) this;
|
||||||
|
}
|
||||||
|
|
||||||
protected EncodingEnum myParamEncoding;
|
protected EncodingEnum myParamEncoding;
|
||||||
protected Boolean myPrettyPrint;
|
protected Boolean myPrettyPrint;
|
||||||
private boolean myQueryLogRequestAndResponse;
|
private boolean myQueryLogRequestAndResponse;
|
||||||
|
@ -925,7 +958,7 @@ public class GenericClient extends BaseClient implements IGenericClient {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Object execute() {
|
public Object execute() {
|
||||||
ResourceResponseHandler binding = new ResourceResponseHandler(myType.getImplementingClass(), null);
|
ResourceResponseHandler binding = new ResourceResponseHandler(myType.getImplementingClass());
|
||||||
HttpGetClientInvocation invocation = MethodUtil.createConformanceInvocation(getFhirContext());
|
HttpGetClientInvocation invocation = MethodUtil.createConformanceInvocation(getFhirContext());
|
||||||
return super.invoke(null, binding, invocation);
|
return super.invoke(null, binding, invocation);
|
||||||
}
|
}
|
||||||
|
@ -963,7 +996,7 @@ public class GenericClient extends BaseClient implements IGenericClient {
|
||||||
if (myBundleType == null) {
|
if (myBundleType == null) {
|
||||||
binding = new BundleResponseHandler(null);
|
binding = new BundleResponseHandler(null);
|
||||||
} else {
|
} else {
|
||||||
binding = new ResourceResponseHandler(myBundleType, null);
|
binding = new ResourceResponseHandler(myBundleType, getPreferResponseTypes());
|
||||||
}
|
}
|
||||||
HttpSimpleGetClientInvocation invocation = new HttpSimpleGetClientInvocation(myContext, myUrl);
|
HttpSimpleGetClientInvocation invocation = new HttpSimpleGetClientInvocation(myContext, myUrl);
|
||||||
|
|
||||||
|
@ -1087,7 +1120,7 @@ public class GenericClient extends BaseClient implements IGenericClient {
|
||||||
|
|
||||||
IClientResponseHandler handler;
|
IClientResponseHandler handler;
|
||||||
if (myReturnType != null) {
|
if (myReturnType != null) {
|
||||||
handler = new ResourceResponseHandler(myReturnType, null);
|
handler = new ResourceResponseHandler(myReturnType, getPreferResponseTypes(myType));
|
||||||
} else {
|
} else {
|
||||||
handler = new BundleResponseHandler(null);
|
handler = new BundleResponseHandler(null);
|
||||||
}
|
}
|
||||||
|
@ -1391,8 +1424,8 @@ public class GenericClient extends BaseClient implements IGenericClient {
|
||||||
|
|
||||||
BaseHttpClientInvocation invocation = OperationMethodBinding.createOperationInvocation(myContext, resourceName, id, myOperationName, myParameters, myUseHttpGet);
|
BaseHttpClientInvocation invocation = OperationMethodBinding.createOperationInvocation(myContext, resourceName, id, myOperationName, myParameters, myUseHttpGet);
|
||||||
|
|
||||||
IClientResponseHandler handler;
|
ResourceResponseHandler handler = new ResourceResponseHandler();
|
||||||
handler = new ResourceResponseHandler(null, null);
|
handler.setPreferResponseTypes(getPreferResponseTypes(myType));
|
||||||
|
|
||||||
Object retVal = invoke(null, handler, invocation);
|
Object retVal = invoke(null, handler, invocation);
|
||||||
if (myContext.getResourceDefinition((IBaseResource) retVal).getName().equals("Parameters")) {
|
if (myContext.getResourceDefinition((IBaseResource) retVal).getName().equals("Parameters")) {
|
||||||
|
@ -1705,7 +1738,7 @@ public class GenericClient extends BaseClient implements IGenericClient {
|
||||||
throws BaseServerResponseException {
|
throws BaseServerResponseException {
|
||||||
if (myContext.getVersion().getVersion().isNewerThan(FhirVersionEnum.DSTU1)) {
|
if (myContext.getVersion().getVersion().isNewerThan(FhirVersionEnum.DSTU1)) {
|
||||||
Class<? extends IBaseResource> bundleType = myContext.getResourceDefinition("Bundle").getImplementingClass();
|
Class<? extends IBaseResource> bundleType = myContext.getResourceDefinition("Bundle").getImplementingClass();
|
||||||
ResourceResponseHandler<IBaseResource> handler = new ResourceResponseHandler<IBaseResource>((Class<IBaseResource>) bundleType, null);
|
ResourceResponseHandler<IBaseResource> handler = new ResourceResponseHandler<IBaseResource>((Class<IBaseResource>) bundleType);
|
||||||
IBaseResource response = handler.invokeClient(theResponseMimeType, theResponseReader, theResponseStatusCode, theHeaders);
|
IBaseResource response = handler.invokeClient(theResponseMimeType, theResponseReader, theResponseStatusCode, theHeaders);
|
||||||
IVersionSpecificBundleFactory bundleFactory = myContext.newBundleFactory();
|
IVersionSpecificBundleFactory bundleFactory = myContext.newBundleFactory();
|
||||||
bundleFactory.initializeWithBundleResource(response);
|
bundleFactory.initializeWithBundleResource(response);
|
||||||
|
@ -1804,7 +1837,7 @@ public class GenericClient extends BaseClient implements IGenericClient {
|
||||||
|
|
||||||
IClientResponseHandler<? extends IBase> binding;
|
IClientResponseHandler<? extends IBase> binding;
|
||||||
if (myReturnBundleType != null) {
|
if (myReturnBundleType != null) {
|
||||||
binding = new ResourceResponseHandler(myReturnBundleType, null);
|
binding = new ResourceResponseHandler(myReturnBundleType, getPreferResponseTypes(myResourceType));
|
||||||
} else {
|
} else {
|
||||||
binding = new BundleResponseHandler(myResourceType);
|
binding = new BundleResponseHandler(myResourceType);
|
||||||
}
|
}
|
||||||
|
@ -2070,13 +2103,13 @@ public class GenericClient extends BaseClient implements IGenericClient {
|
||||||
BaseHttpClientInvocation invocation = TransactionMethodBinding.createTransactionInvocation(myResources, myContext);
|
BaseHttpClientInvocation invocation = TransactionMethodBinding.createTransactionInvocation(myResources, myContext);
|
||||||
return (T) invoke(params, binding, invocation);
|
return (T) invoke(params, binding, invocation);
|
||||||
} else if (myBaseBundle != null) {
|
} else if (myBaseBundle != null) {
|
||||||
ResourceResponseHandler binding = new ResourceResponseHandler(myBaseBundle.getClass(), null);
|
ResourceResponseHandler binding = new ResourceResponseHandler(myBaseBundle.getClass(), getPreferResponseTypes());
|
||||||
BaseHttpClientInvocation invocation = TransactionMethodBinding.createTransactionInvocation(myBaseBundle, myContext);
|
BaseHttpClientInvocation invocation = TransactionMethodBinding.createTransactionInvocation(myBaseBundle, myContext);
|
||||||
return (T) invoke(params, binding, invocation);
|
return (T) invoke(params, binding, invocation);
|
||||||
} else if (myRawBundle != null) {
|
} else if (myRawBundle != null) {
|
||||||
StringResponseHandler binding = new StringResponseHandler();
|
StringResponseHandler binding = new StringResponseHandler();
|
||||||
/*
|
/*
|
||||||
* If the user has explicitly requested a given encoding, we may need to reencode the raw string
|
* If the user has explicitly requested a given encoding, we may need to re-encode the raw string
|
||||||
*/
|
*/
|
||||||
if (getParamEncoding() != null) {
|
if (getParamEncoding() != null) {
|
||||||
if (MethodUtil.detectEncodingNoDefault(myRawBundle) != getParamEncoding()) {
|
if (MethodUtil.detectEncodingNoDefault(myRawBundle) != getParamEncoding()) {
|
||||||
|
|
|
@ -1,5 +1,9 @@
|
||||||
package ca.uhn.fhir.rest.gclient;
|
package ca.uhn.fhir.rest.gclient;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||||
|
|
||||||
import ca.uhn.fhir.rest.api.SummaryEnum;
|
import ca.uhn.fhir.rest.api.SummaryEnum;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -49,6 +53,27 @@ public interface IClientExecutable<T extends IClientExecutable<?,?>, Y> {
|
||||||
|
|
||||||
T prettyPrint();
|
T prettyPrint();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Explicitly specify a custom structure type to attempt to use when parsing the response. This
|
||||||
|
* is useful for invocations where the response is a Bundle/Parameters containing nested resources,
|
||||||
|
* and you want to use specific custom structures for those nested resources.
|
||||||
|
* <p>
|
||||||
|
* See <a href="https://jamesagnew.github.io/hapi-fhir/doc_extensions.html">Profiles and Extensions</a> for more information on using custom structures
|
||||||
|
* </p>
|
||||||
|
*/
|
||||||
|
T preferResponseType(Class<? extends IBaseResource> theType);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Explicitly specify a list of custom structure types to attempt to use (in order from most to
|
||||||
|
* least preferred) when parsing the response. This
|
||||||
|
* is useful for invocations where the response is a Bundle/Parameters containing nested resources,
|
||||||
|
* and you want to use specific custom structures for those nested resources.
|
||||||
|
* <p>
|
||||||
|
* See <a href="https://jamesagnew.github.io/hapi-fhir/doc_extensions.html">Profiles and Extensions</a> for more information on using custom structures
|
||||||
|
* </p>
|
||||||
|
*/
|
||||||
|
T preferResponseTypes(List<Class<? extends IBaseResource>> theTypes);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Request that the server modify the response using the <code>_summary</code> param
|
* Request that the server modify the response using the <code>_summary</code> param
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -38,7 +38,7 @@ public class CustomTypeDstu3Test {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private String createBundle(String... theResources) {
|
public static String createBundle(String... theResources) {
|
||||||
StringBuilder b = new StringBuilder();
|
StringBuilder b = new StringBuilder();
|
||||||
b.append("<Bundle xmlns=\"http://hl7.org/fhir\">\n");
|
b.append("<Bundle xmlns=\"http://hl7.org/fhir\">\n");
|
||||||
for (String next : theResources) {
|
for (String next : theResources) {
|
||||||
|
@ -52,7 +52,7 @@ public class CustomTypeDstu3Test {
|
||||||
return b.toString();
|
return b.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
private String createResource(boolean theWithProfile) {
|
public static String createResource(boolean theWithProfile) {
|
||||||
StringBuilder b = new StringBuilder();
|
StringBuilder b = new StringBuilder();
|
||||||
b.append("<Patient xmlns=\"http://hl7.org/fhir\">\n");
|
b.append("<Patient xmlns=\"http://hl7.org/fhir\">\n");
|
||||||
if (theWithProfile) {
|
if (theWithProfile) {
|
||||||
|
@ -120,7 +120,6 @@ public class CustomTypeDstu3Test {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void parseBundleWithResourceDirective() {
|
public void parseBundleWithResourceDirective() {
|
||||||
|
|
||||||
String input = createBundle(createResource(false), createResource(true));
|
String input = createBundle(createResource(false), createResource(true));
|
||||||
|
|
||||||
FhirContext ctx = FhirContext.forDstu3();
|
FhirContext ctx = FhirContext.forDstu3();
|
||||||
|
|
|
@ -10,7 +10,9 @@ import static org.mockito.Mockito.when;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.StringReader;
|
import java.io.StringReader;
|
||||||
import java.nio.charset.Charset;
|
import java.nio.charset.Charset;
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
import org.apache.commons.io.IOUtils;
|
import org.apache.commons.io.IOUtils;
|
||||||
import org.apache.commons.io.input.ReaderInputStream;
|
import org.apache.commons.io.input.ReaderInputStream;
|
||||||
|
@ -22,9 +24,12 @@ import org.apache.http.client.methods.HttpUriRequest;
|
||||||
import org.apache.http.message.BasicHeader;
|
import org.apache.http.message.BasicHeader;
|
||||||
import org.apache.http.message.BasicStatusLine;
|
import org.apache.http.message.BasicStatusLine;
|
||||||
import org.hl7.fhir.dstu3.model.Binary;
|
import org.hl7.fhir.dstu3.model.Binary;
|
||||||
|
import org.hl7.fhir.dstu3.model.Bundle;
|
||||||
import org.hl7.fhir.dstu3.model.Conformance;
|
import org.hl7.fhir.dstu3.model.Conformance;
|
||||||
import org.hl7.fhir.dstu3.model.OperationOutcome;
|
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.dstu3.model.Patient;
|
||||||
|
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.BeforeClass;
|
import org.junit.BeforeClass;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
@ -34,6 +39,8 @@ import org.mockito.invocation.InvocationOnMock;
|
||||||
import org.mockito.stubbing.Answer;
|
import org.mockito.stubbing.Answer;
|
||||||
|
|
||||||
import ca.uhn.fhir.context.FhirContext;
|
import ca.uhn.fhir.context.FhirContext;
|
||||||
|
import ca.uhn.fhir.parser.CustomTypeDstu3Test;
|
||||||
|
import ca.uhn.fhir.parser.CustomTypeDstu3Test.MyCustomPatient;
|
||||||
import ca.uhn.fhir.parser.IParser;
|
import ca.uhn.fhir.parser.IParser;
|
||||||
import ca.uhn.fhir.rest.server.Constants;
|
import ca.uhn.fhir.rest.server.Constants;
|
||||||
import ca.uhn.fhir.util.VersionUtil;
|
import ca.uhn.fhir.util.VersionUtil;
|
||||||
|
@ -88,6 +95,163 @@ public class GenericClientDstu3Test {
|
||||||
validateUserAgent(capt);
|
validateUserAgent(capt);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testExplicitCustomTypeSearch() throws Exception {
|
||||||
|
final String respString = CustomTypeDstu3Test.createBundle(CustomTypeDstu3Test.createResource(false));
|
||||||
|
ArgumentCaptor<HttpUriRequest> 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<ReaderInputStream>() {
|
||||||
|
@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");
|
||||||
|
|
||||||
|
//@formatter:off
|
||||||
|
Bundle resp = client
|
||||||
|
.search()
|
||||||
|
.forResource(CustomTypeDstu3Test.MyCustomPatient.class)
|
||||||
|
.returnBundle(Bundle.class)
|
||||||
|
.execute();
|
||||||
|
//@formatter:on
|
||||||
|
|
||||||
|
assertEquals(1, resp.getEntry().size());
|
||||||
|
assertEquals(CustomTypeDstu3Test.MyCustomPatient.class, resp.getEntry().get(0).getResource().getClass());
|
||||||
|
assertEquals("http://example.com/fhir/Patient", capt.getAllValues().get(0).getURI().toASCIIString());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testExplicitCustomTypeHistoryType() throws Exception {
|
||||||
|
final String respString = CustomTypeDstu3Test.createBundle(CustomTypeDstu3Test.createResource(false));
|
||||||
|
ArgumentCaptor<HttpUriRequest> 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<ReaderInputStream>() {
|
||||||
|
@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");
|
||||||
|
|
||||||
|
//@formatter:off
|
||||||
|
Bundle resp = client
|
||||||
|
.history()
|
||||||
|
.onType(CustomTypeDstu3Test.MyCustomPatient.class)
|
||||||
|
.andReturnBundle(Bundle.class)
|
||||||
|
.execute();
|
||||||
|
//@formatter:on
|
||||||
|
|
||||||
|
assertEquals(1, resp.getEntry().size());
|
||||||
|
assertEquals(CustomTypeDstu3Test.MyCustomPatient.class, resp.getEntry().get(0).getResource().getClass());
|
||||||
|
assertEquals("http://example.com/fhir/Patient/_history", capt.getAllValues().get(0).getURI().toASCIIString());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testExplicitCustomTypeLoadPage() throws Exception {
|
||||||
|
final String respString = CustomTypeDstu3Test.createBundle(CustomTypeDstu3Test.createResource(false));
|
||||||
|
ArgumentCaptor<HttpUriRequest> 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<ReaderInputStream>() {
|
||||||
|
@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 = new Bundle();
|
||||||
|
bundle.addLink().setRelation("next").setUrl("http://foo/next");
|
||||||
|
|
||||||
|
//@formatter:off
|
||||||
|
Bundle resp = client
|
||||||
|
.loadPage()
|
||||||
|
.next(bundle)
|
||||||
|
.preferResponseType(MyCustomPatient.class)
|
||||||
|
.execute();
|
||||||
|
//@formatter:on
|
||||||
|
|
||||||
|
assertEquals(1, resp.getEntry().size());
|
||||||
|
assertEquals(CustomTypeDstu3Test.MyCustomPatient.class, resp.getEntry().get(0).getResource().getClass());
|
||||||
|
assertEquals("http://foo/next", capt.getAllValues().get(0).getURI().toASCIIString());
|
||||||
|
|
||||||
|
//@formatter:off
|
||||||
|
resp = client
|
||||||
|
.loadPage()
|
||||||
|
.next(bundle)
|
||||||
|
.preferResponseTypes(toTypeList(MyCustomPatient.class))
|
||||||
|
.execute();
|
||||||
|
//@formatter:on
|
||||||
|
|
||||||
|
assertEquals(1, resp.getEntry().size());
|
||||||
|
assertEquals(CustomTypeDstu3Test.MyCustomPatient.class, resp.getEntry().get(0).getResource().getClass());
|
||||||
|
assertEquals("http://foo/next", capt.getAllValues().get(0).getURI().toASCIIString());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testExplicitCustomTypeOperation() throws Exception {
|
||||||
|
|
||||||
|
Parameters param = new Parameters();
|
||||||
|
Patient patient = new Patient();
|
||||||
|
patient.addName().addFamily("FOO");
|
||||||
|
param.addParameter().setName("foo").setResource(patient);
|
||||||
|
final String respString = ourCtx.newXmlParser().encodeResourceToString(param);
|
||||||
|
|
||||||
|
ArgumentCaptor<HttpUriRequest> 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<ReaderInputStream>() {
|
||||||
|
@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");
|
||||||
|
|
||||||
|
//@formatter:off
|
||||||
|
Parameters resp = client
|
||||||
|
.operation()
|
||||||
|
.onServer()
|
||||||
|
.named("foo")
|
||||||
|
.withNoParameters(Parameters.class)
|
||||||
|
.preferResponseType(MyCustomPatient.class)
|
||||||
|
.execute();
|
||||||
|
//@formatter:on
|
||||||
|
|
||||||
|
assertEquals(1, resp.getParameter().size());
|
||||||
|
assertEquals(CustomTypeDstu3Test.MyCustomPatient.class, resp.getParameter().get(0).getResource().getClass());
|
||||||
|
assertEquals("http://example.com/fhir/$foo", capt.getAllValues().get(0).getURI().toASCIIString());
|
||||||
|
|
||||||
|
//@formatter:off
|
||||||
|
resp = client
|
||||||
|
.operation()
|
||||||
|
.onType(MyCustomPatient.class)
|
||||||
|
.named("foo")
|
||||||
|
.withNoParameters(Parameters.class)
|
||||||
|
.execute();
|
||||||
|
//@formatter:on
|
||||||
|
|
||||||
|
assertEquals(1, resp.getParameter().size());
|
||||||
|
assertEquals(CustomTypeDstu3Test.MyCustomPatient.class, resp.getParameter().get(0).getResource().getClass());
|
||||||
|
assertEquals("http://example.com/fhir/Patient/$foo", capt.getAllValues().get(1).getURI().toASCIIString());
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<Class<? extends IBaseResource>> toTypeList(Class<? extends IBaseResource> theClass) {
|
||||||
|
ArrayList<Class<? extends IBaseResource>> retVal = new ArrayList<Class<? extends IBaseResource>>();
|
||||||
|
retVal.add(theClass);
|
||||||
|
return retVal;
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testUserAgentForBinary() throws Exception {
|
public void testUserAgentForBinary() throws Exception {
|
||||||
IParser p = ourCtx.newXmlParser();
|
IParser p = ourCtx.newXmlParser();
|
||||||
|
|
|
@ -185,6 +185,29 @@
|
||||||
<param name="file" value="examples/src/main/java/example/ExtensionsDstu3.java" />
|
<param name="file" value="examples/src/main/java/example/ExtensionsDstu3.java" />
|
||||||
</macro>
|
</macro>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
You may also explicitly use custom types in searches and other
|
||||||
|
operations which return resources.
|
||||||
|
</p>
|
||||||
|
<macro name="snippet">
|
||||||
|
<param name="id" value="customTypeClientSearch" />
|
||||||
|
<param name="file" value="examples/src/main/java/example/ExtensionsDstu3.java" />
|
||||||
|
</macro>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
You can also explicitly declare a preferred response resource custom
|
||||||
|
type. This is useful for some operations that do not otherwise
|
||||||
|
declare their resource types in the method signature.
|
||||||
|
</p>
|
||||||
|
<macro name="snippet">
|
||||||
|
<param name="id" value="customTypeClientSearch2" />
|
||||||
|
<param name="file" value="examples/src/main/java/example/ExtensionsDstu3.java" />
|
||||||
|
</macro>
|
||||||
|
|
||||||
|
</subsection>
|
||||||
|
|
||||||
|
<subsection name="Using Multiple Custom Types in a Client">
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
Sometimes you may not know in advance exactly which
|
Sometimes you may not know in advance exactly which
|
||||||
type you will be receiving. For example, there are Patient resources
|
type you will be receiving. For example, there are Patient resources
|
||||||
|
@ -192,6 +215,11 @@
|
||||||
aren't sure which profile you will get back for a specific read,
|
aren't sure which profile you will get back for a specific read,
|
||||||
you can declare the "primary" type for a given profile.
|
you can declare the "primary" type for a given profile.
|
||||||
</p>
|
</p>
|
||||||
|
<p>
|
||||||
|
This is declared at the FhirContext level, and will apply to any
|
||||||
|
clients created from this context (including clients created before
|
||||||
|
the default was set).
|
||||||
|
</p>
|
||||||
<macro name="snippet">
|
<macro name="snippet">
|
||||||
<param name="id" value="customTypeClientDeclared" />
|
<param name="id" value="customTypeClientDeclared" />
|
||||||
<param name="file" value="examples/src/main/java/example/ExtensionsDstu3.java" />
|
<param name="file" value="examples/src/main/java/example/ExtensionsDstu3.java" />
|
||||||
|
|
Loading…
Reference in New Issue