Fix #403 - Allow references to keep versions when encoding
This commit is contained in:
parent
c532d1a25b
commit
350e82b6cf
|
@ -0,0 +1,42 @@
|
|||
package example;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.parser.DataFormatException;
|
||||
import ca.uhn.fhir.parser.IParser;
|
||||
|
||||
public class Parser {
|
||||
|
||||
public static void main(String[] args) throws DataFormatException, IOException {
|
||||
{
|
||||
//START SNIPPET: disableStripVersions
|
||||
FhirContext ctx = FhirContext.forDstu2();
|
||||
IParser parser = ctx.newJsonParser();
|
||||
|
||||
// Disable the automatic stripping of versions from references on the parser
|
||||
parser.setStripVersionsFromReferences(false);
|
||||
//END SNIPPET: disableStripVersions
|
||||
|
||||
//START SNIPPET: disableStripVersionsCtx
|
||||
ctx.getParserOptions().setStripVersionsFromReferences(false);
|
||||
//END SNIPPET: disableStripVersionsCtx
|
||||
|
||||
}
|
||||
|
||||
{
|
||||
//START SNIPPET: disableStripVersionsField
|
||||
FhirContext ctx = FhirContext.forDstu2();
|
||||
IParser parser = ctx.newJsonParser();
|
||||
|
||||
// Preserve versions only on these two fields (for the given parser)
|
||||
parser.setDontStripVersionsFromReferencesAtPaths("AuditEvent.entity.reference", "Patient.managingOrganization");
|
||||
|
||||
// You can also apply this setting to the context so that it will
|
||||
// flow to all parsers
|
||||
ctx.getParserOptions().setDontStripVersionsFromReferencesAtPaths("AuditEvent.entity.reference", "Patient.managingOrganization");
|
||||
//END SNIPPET: disableStripVersionsField
|
||||
|
||||
}
|
||||
}
|
||||
}
|
|
@ -103,6 +103,28 @@ public class FhirContext {
|
|||
private final IFhirVersion myVersion;
|
||||
private Map<FhirVersionEnum, Map<String, Class<? extends IBaseResource>>> myVersionToNameToResourceType = Collections.emptyMap();
|
||||
private boolean myInitializing;
|
||||
private ParserOptions myParserOptions = new ParserOptions();
|
||||
|
||||
/**
|
||||
* Returns the parser options object which will be used to supply default
|
||||
* options to newly created parsers
|
||||
*
|
||||
* @return The parser options - Will not return <code>null</code>
|
||||
*/
|
||||
public ParserOptions getParserOptions() {
|
||||
return myParserOptions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the parser options object which will be used to supply default
|
||||
* options to newly created parsers
|
||||
*
|
||||
* @param theParserOptions The parser options object - Must not be <code>null</code>
|
||||
*/
|
||||
public void setParserOptions(ParserOptions theParserOptions) {
|
||||
Validate.notNull(theParserOptions, "theParserOptions must not be null");
|
||||
myParserOptions = theParserOptions;
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated It is recommended that you use one of the static initializer methods instead
|
||||
|
|
|
@ -0,0 +1,127 @@
|
|||
package ca.uhn.fhir.context;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import ca.uhn.fhir.parser.IParser;
|
||||
|
||||
/**
|
||||
* This object supplies default configuration to all {@link IParser parser} instances
|
||||
* created by a given {@link FhirContext}. It is accessed using {@link FhirContext#getParserOptions()}
|
||||
* and {@link FhirContext#setParserOptions(ParserOptions)}.
|
||||
* <p>
|
||||
* It is fine to share a ParserOptions instances across multiple context instances.
|
||||
* </p>
|
||||
*/
|
||||
public class ParserOptions {
|
||||
|
||||
private boolean myStripVersionsFromReferences = true;
|
||||
private Set<String> myDontStripVersionsFromReferencesAtPaths = Collections.emptySet();
|
||||
|
||||
/**
|
||||
* If supplied value(s), any resource references at the specified paths will have their
|
||||
* resource versions encoded instead of being automatically stripped during the encoding
|
||||
* process. This setting has no effect on the parsing process.
|
||||
* <p>
|
||||
* This method provides a finer-grained level of control than {@link #setStripVersionsFromReferences(boolean)}
|
||||
* and any paths specified by this method will be encoded even if {@link #setStripVersionsFromReferences(boolean)}
|
||||
* has been set to <code>true</code> (which is the default)
|
||||
* </p>
|
||||
*
|
||||
* @param thePaths
|
||||
* A collection of paths for which the resource versions will not be removed automatically
|
||||
* when serializing, e.g. "Patient.managingOrganization" or "AuditEvent.object.reference". Note that
|
||||
* only resource name and field names with dots separating is allowed here (no repetition
|
||||
* indicators, FluentPath expressions, etc.)
|
||||
* @see #setStripVersionsFromReferences(boolean)
|
||||
* @return Returns a reference to <code>this</code> parser so that method calls can be chained together
|
||||
*/
|
||||
public ParserOptions setDontStripVersionsFromReferencesAtPaths(String... thePaths) {
|
||||
if (thePaths == null) {
|
||||
setDontStripVersionsFromReferencesAtPaths((List<String>) null);
|
||||
} else {
|
||||
setDontStripVersionsFromReferencesAtPaths(Arrays.asList(thePaths));
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* If set to <code>true<code> (which is the default), resource references containing a version
|
||||
* will have the version removed when the resource is encoded. This is generally good behaviour because
|
||||
* in most situations, references from one resource to another should be to the resource by ID, not
|
||||
* by ID and version. In some cases though, it may be desirable to preserve the version in resource
|
||||
* links. In that case, this value should be set to <code>false</code>.
|
||||
*
|
||||
* @return Returns the parser instance's configuration setting for stripping versions from resource references when
|
||||
* encoding. Default is <code>true</code>.
|
||||
*/
|
||||
public boolean isStripVersionsFromReferences() {
|
||||
return myStripVersionsFromReferences ;
|
||||
}
|
||||
|
||||
/**
|
||||
* If set to <code>true<code> (which is the default), resource references containing a version
|
||||
* will have the version removed when the resource is encoded. This is generally good behaviour because
|
||||
* in most situations, references from one resource to another should be to the resource by ID, not
|
||||
* by ID and version. In some cases though, it may be desirable to preserve the version in resource
|
||||
* links. In that case, this value should be set to <code>false</code>.
|
||||
* <p>
|
||||
* This method provides the ability to globally disable reference encoding. If finer-grained
|
||||
* control is needed, use {@link #setDontStripVersionsFromReferencesAtPaths(String...)}
|
||||
* </p>
|
||||
* @param theStripVersionsFromReferences
|
||||
* Set this to <code>false<code> to prevent the parser from removing
|
||||
* resource versions from references.
|
||||
* @return Returns a reference to <code>this</code> parser so that method calls can be chained together
|
||||
* @see #setDontStripVersionsFromReferencesAtPaths(String...)
|
||||
*/
|
||||
public ParserOptions setStripVersionsFromReferences(boolean theStripVersionsFromReferences) {
|
||||
myStripVersionsFromReferences = theStripVersionsFromReferences;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* If supplied value(s), any resource references at the specified paths will have their
|
||||
* resource versions encoded instead of being automatically stripped during the encoding
|
||||
* process. This setting has no effect on the parsing process.
|
||||
* <p>
|
||||
* This method provides a finer-grained level of control than {@link #setStripVersionsFromReferences(boolean)}
|
||||
* and any paths specified by this method will be encoded even if {@link #setStripVersionsFromReferences(boolean)}
|
||||
* has been set to <code>true</code> (which is the default)
|
||||
* </p>
|
||||
*
|
||||
* @param thePaths
|
||||
* A collection of paths for which the resource versions will not be removed automatically
|
||||
* when serializing, e.g. "Patient.managingOrganization" or "AuditEvent.object.reference". Note that
|
||||
* only resource name and field names with dots separating is allowed here (no repetition
|
||||
* indicators, FluentPath expressions, etc.)
|
||||
* @see #setStripVersionsFromReferences(boolean)
|
||||
* @return Returns a reference to <code>this</code> parser so that method calls can be chained together
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public ParserOptions setDontStripVersionsFromReferencesAtPaths(Collection<String> thePaths) {
|
||||
if (thePaths == null) {
|
||||
myDontStripVersionsFromReferencesAtPaths = Collections.emptySet();
|
||||
} else if (thePaths instanceof HashSet) {
|
||||
myDontStripVersionsFromReferencesAtPaths = (Set<String>) ((HashSet<String>)thePaths).clone();
|
||||
} else {
|
||||
myDontStripVersionsFromReferencesAtPaths = new HashSet<String>(thePaths);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the value supplied to {@link IParser#setDontStripVersionsFromReferencesAtPaths(String...)}
|
||||
*
|
||||
* @see #setDontStripVersionsFromReferencesAtPaths(String...)
|
||||
* @see #setStripVersionsFromReferences(boolean)
|
||||
*/
|
||||
public Set<String> getDontStripVersionsFromReferencesAtPaths() {
|
||||
return myDontStripVersionsFromReferencesAtPaths;
|
||||
}
|
||||
|
||||
}
|
|
@ -29,6 +29,8 @@ import java.io.StringWriter;
|
|||
import java.io.Writer;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
|
@ -93,9 +95,11 @@ public abstract class BaseParser implements IParser {
|
|||
private boolean myOmitResourceId;
|
||||
private List<Class<? extends IBaseResource>> myPreferTypes;
|
||||
private String myServerBaseUrl;
|
||||
private boolean myStripVersionsFromReferences = true;
|
||||
private Boolean myStripVersionsFromReferences;
|
||||
private boolean mySummaryMode;
|
||||
private boolean mySuppressNarratives;
|
||||
private Set<String> myDontStripVersionsFromReferencesAtPaths;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
|
@ -265,7 +269,7 @@ public abstract class BaseParser implements IParser {
|
|||
myContainedResources = contained;
|
||||
}
|
||||
|
||||
private String determineReferenceText(IBaseReference theRef) {
|
||||
private String determineReferenceText(IBaseReference theRef, CompositeChildElement theCompositeChildElement) {
|
||||
IIdType ref = theRef.getReferenceElement();
|
||||
if (isBlank(ref.getIdPart())) {
|
||||
String reference = ref.getValue();
|
||||
|
@ -284,7 +288,7 @@ public abstract class BaseParser implements IParser {
|
|||
if (!refId.hasResourceType()) {
|
||||
refId = refId.withResourceType(myContext.getResourceDefinition(theRef.getResource()).getName());
|
||||
}
|
||||
if (isStripVersionsFromReferences()) {
|
||||
if (isStripVersionsFromReferences(theCompositeChildElement)) {
|
||||
reference = refId.toVersionless().getValue();
|
||||
} else {
|
||||
reference = refId.getValue();
|
||||
|
@ -299,13 +303,13 @@ public abstract class BaseParser implements IParser {
|
|||
ref = ref.withResourceType(myContext.getResourceDefinition(theRef.getResource()).getName());
|
||||
}
|
||||
if (isNotBlank(myServerBaseUrl) && StringUtils.equals(myServerBaseUrl, ref.getBaseUrl())) {
|
||||
if (isStripVersionsFromReferences()) {
|
||||
if (isStripVersionsFromReferences(theCompositeChildElement)) {
|
||||
return ref.toUnqualifiedVersionless().getValue();
|
||||
} else {
|
||||
return ref.toUnqualified().getValue();
|
||||
}
|
||||
} else {
|
||||
if (isStripVersionsFromReferences()) {
|
||||
if (isStripVersionsFromReferences(theCompositeChildElement)) {
|
||||
return ref.toVersionless().getValue();
|
||||
} else {
|
||||
return ref.getValue();
|
||||
|
@ -314,6 +318,31 @@ public abstract class BaseParser implements IParser {
|
|||
}
|
||||
}
|
||||
|
||||
private boolean isStripVersionsFromReferences(CompositeChildElement theCompositeChildElement) {
|
||||
Boolean stripVersionsFromReferences = myStripVersionsFromReferences;
|
||||
if (stripVersionsFromReferences != null) {
|
||||
return stripVersionsFromReferences;
|
||||
}
|
||||
|
||||
if (myContext.getParserOptions().isStripVersionsFromReferences() == false) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Set<String> dontStripVersionsFromReferencesAtPaths = myDontStripVersionsFromReferencesAtPaths;
|
||||
if (dontStripVersionsFromReferencesAtPaths != null) {
|
||||
if (dontStripVersionsFromReferencesAtPaths.isEmpty() == false && theCompositeChildElement.anyPathMatches(dontStripVersionsFromReferencesAtPaths)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
dontStripVersionsFromReferencesAtPaths = myContext.getParserOptions().getDontStripVersionsFromReferencesAtPaths();
|
||||
if (dontStripVersionsFromReferencesAtPaths.isEmpty() == false && theCompositeChildElement.anyPathMatches(dontStripVersionsFromReferencesAtPaths)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
protected abstract void doEncodeBundleToWriter(Bundle theBundle, Writer theWriter) throws IOException, DataFormatException;
|
||||
|
||||
protected abstract void doEncodeResourceToWriter(IBaseResource theResource, Writer theWriter) throws IOException, DataFormatException;
|
||||
|
@ -401,10 +430,10 @@ public abstract class BaseParser implements IParser {
|
|||
String childName = theChild.getChildNameByDatatype(type);
|
||||
BaseRuntimeElementDefinition<?> childDef = theChild.getChildElementDefinitionByDatatype(type);
|
||||
if (childDef == null) {
|
||||
// if (theValue instanceof IBaseExtension) {
|
||||
// return null;
|
||||
// }
|
||||
|
||||
// if (theValue instanceof IBaseExtension) {
|
||||
// return null;
|
||||
// }
|
||||
|
||||
/*
|
||||
* For RI structures Enumeration class, this replaces the child def
|
||||
* with the "code" one. This is messy, and presumably there is a better
|
||||
|
@ -431,12 +460,12 @@ public abstract class BaseParser implements IParser {
|
|||
nextSuperType = nextSuperType.getSuperclass();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (childDef == null) {
|
||||
throwExceptionForUnknownChildType(theChild, type);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return new ChildNameAndDef(childName, childDef);
|
||||
}
|
||||
|
||||
|
@ -558,7 +587,7 @@ public abstract class BaseParser implements IParser {
|
|||
}
|
||||
|
||||
@Override
|
||||
public boolean isStripVersionsFromReferences() {
|
||||
public Boolean getStripVersionsFromReferences() {
|
||||
return myStripVersionsFromReferences;
|
||||
}
|
||||
|
||||
|
@ -667,7 +696,7 @@ public abstract class BaseParser implements IParser {
|
|||
return parseTagList(new StringReader(theString));
|
||||
}
|
||||
|
||||
protected List<? extends IBase> preProcessValues(BaseRuntimeChildDefinition theMetaChildUncast, IBaseResource theResource, List<? extends IBase> theValues) {
|
||||
protected List<? extends IBase> preProcessValues(BaseRuntimeChildDefinition theMetaChildUncast, IBaseResource theResource, List<? extends IBase> theValues, CompositeChildElement theCompositeChildElement) {
|
||||
if (myContext.getVersion().getVersion().isRi()) {
|
||||
|
||||
/*
|
||||
|
@ -736,7 +765,7 @@ public abstract class BaseParser implements IParser {
|
|||
*/
|
||||
if (next instanceof IBaseReference) {
|
||||
IBaseReference nextRef = (IBaseReference) next;
|
||||
String refText = determineReferenceText(nextRef);
|
||||
String refText = determineReferenceText(nextRef, theCompositeChildElement);
|
||||
if (!StringUtils.equals(refText, nextRef.getReferenceElement().getValue())) {
|
||||
|
||||
if (retVal == theValues) {
|
||||
|
@ -824,11 +853,39 @@ public abstract class BaseParser implements IParser {
|
|||
}
|
||||
|
||||
@Override
|
||||
public IParser setStripVersionsFromReferences(boolean theStripVersionsFromReferences) {
|
||||
public IParser setStripVersionsFromReferences(Boolean theStripVersionsFromReferences) {
|
||||
myStripVersionsFromReferences = theStripVersionsFromReferences;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IParser setDontStripVersionsFromReferencesAtPaths(String... thePaths) {
|
||||
if (thePaths == null) {
|
||||
setDontStripVersionsFromReferencesAtPaths((List<String>) null);
|
||||
} else {
|
||||
setDontStripVersionsFromReferencesAtPaths(Arrays.asList(thePaths));
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public IParser setDontStripVersionsFromReferencesAtPaths(Collection<String> thePaths) {
|
||||
if (thePaths == null) {
|
||||
myDontStripVersionsFromReferencesAtPaths = Collections.emptySet();
|
||||
} else if (thePaths instanceof HashSet) {
|
||||
myDontStripVersionsFromReferencesAtPaths = (Set<String>) ((HashSet<String>) thePaths).clone();
|
||||
} else {
|
||||
myDontStripVersionsFromReferencesAtPaths = new HashSet<String>(thePaths);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<String> getDontStripVersionsFromReferencesAtPaths() {
|
||||
return myDontStripVersionsFromReferencesAtPaths;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IParser setSummaryMode(boolean theSummaryMode) {
|
||||
mySummaryMode = theSummaryMode;
|
||||
|
@ -970,6 +1027,34 @@ public abstract class BaseParser implements IParser {
|
|||
|
||||
}
|
||||
|
||||
public boolean anyPathMatches(Set<String> thePaths) {
|
||||
StringBuilder b = new StringBuilder();
|
||||
addParent(this, b);
|
||||
|
||||
String path = b.toString();
|
||||
return thePaths.contains(path);
|
||||
}
|
||||
|
||||
private void addParent(CompositeChildElement theParent, StringBuilder theB) {
|
||||
if (theParent != null) {
|
||||
if (theParent.myResDef != null) {
|
||||
theB.append(theParent.myResDef.getName());
|
||||
return;
|
||||
}
|
||||
|
||||
if (theParent.myParent != null) {
|
||||
addParent(theParent.myParent, theB);
|
||||
}
|
||||
|
||||
if (theParent.myDef != null) {
|
||||
if (theB.length() > 0) {
|
||||
theB.append('.');
|
||||
}
|
||||
theB.append(theParent.myDef.getElementName());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public CompositeChildElement(RuntimeResourceDefinition theResDef) {
|
||||
myResDef = theResDef;
|
||||
myDef = null;
|
||||
|
@ -992,14 +1077,14 @@ public abstract class BaseParser implements IParser {
|
|||
}
|
||||
|
||||
private boolean checkIfParentShouldBeEncodedAndBuildPath(StringBuilder thePathBuilder, boolean theStarPass) {
|
||||
return checkIfPathMatches(thePathBuilder, theStarPass, myEncodeElementsAppliesToResourceTypes, myEncodeElements, true);
|
||||
return checkIfPathMatchesForEncoding(thePathBuilder, theStarPass, myEncodeElementsAppliesToResourceTypes, myEncodeElements, true);
|
||||
}
|
||||
|
||||
private boolean checkIfParentShouldNotBeEncodedAndBuildPath(StringBuilder thePathBuilder, boolean theStarPass) {
|
||||
return checkIfPathMatches(thePathBuilder, theStarPass, null, myDontEncodeElements, false);
|
||||
return checkIfPathMatchesForEncoding(thePathBuilder, theStarPass, null, myDontEncodeElements, false);
|
||||
}
|
||||
|
||||
private boolean checkIfPathMatches(StringBuilder thePathBuilder, boolean theStarPass, Set<String> theResourceTypes, Set<String> theElements, boolean theCheckingForWhitelist) {
|
||||
private boolean checkIfPathMatchesForEncoding(StringBuilder thePathBuilder, boolean theStarPass, Set<String> theResourceTypes, Set<String> theElements, boolean theCheckingForWhitelist) {
|
||||
if (myResDef != null) {
|
||||
if (theResourceTypes != null) {
|
||||
if (!theResourceTypes.contains(myResDef.getName())) {
|
||||
|
@ -1069,12 +1154,12 @@ public abstract class BaseParser implements IParser {
|
|||
retVal = !checkIfParentShouldNotBeEncodedAndBuildPath(new StringBuilder(), true);
|
||||
}
|
||||
}
|
||||
// if (retVal == false && myEncodeElements.contains("*.(mandatory)")) {
|
||||
// if (myDef.getMin() > 0) {
|
||||
// retVal = true;
|
||||
// }
|
||||
// }
|
||||
|
||||
// if (retVal == false && myEncodeElements.contains("*.(mandatory)")) {
|
||||
// if (myDef.getMin() > 0) {
|
||||
// retVal = true;
|
||||
// }
|
||||
// }
|
||||
|
||||
return retVal;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -23,6 +23,7 @@ package ca.uhn.fhir.parser;
|
|||
import java.io.IOException;
|
||||
import java.io.Reader;
|
||||
import java.io.Writer;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
|
@ -32,6 +33,7 @@ import org.hl7.fhir.instance.model.api.IIdType;
|
|||
|
||||
import ca.uhn.fhir.context.ConfigurationException;
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.context.ParserOptions;
|
||||
import ca.uhn.fhir.model.api.Bundle;
|
||||
import ca.uhn.fhir.model.api.IResource;
|
||||
import ca.uhn.fhir.model.api.TagList;
|
||||
|
@ -64,7 +66,7 @@ public interface IParser {
|
|||
* @return An encoded tag list
|
||||
*/
|
||||
String encodeTagListToString(TagList theTagList);
|
||||
|
||||
|
||||
/**
|
||||
* Encodes a tag list, as defined in the <a href="http://hl7.org/implement/standards/fhir/http.html#tags">FHIR
|
||||
* Specification</a>.
|
||||
|
@ -75,7 +77,7 @@ public interface IParser {
|
|||
* The writer to encode to
|
||||
*/
|
||||
void encodeTagListToWriter(TagList theTagList, Writer theWriter) throws IOException;
|
||||
|
||||
|
||||
/**
|
||||
* See {@link #setEncodeElements(Set)}
|
||||
*/
|
||||
|
@ -121,9 +123,11 @@ public interface IParser {
|
|||
* links. In that case, this value should be set to <code>false</code>.
|
||||
*
|
||||
* @return Returns the parser instance's configuration setting for stripping versions from resource references when
|
||||
* encoding. Default is <code>true</code>.
|
||||
* encoding. This method will retun <code>null</code> if no value is set, in which case
|
||||
* the value from the {@link ParserOptions} will be used (default is <code>true</code>)
|
||||
* @see ParserOptions
|
||||
*/
|
||||
boolean isStripVersionsFromReferences();
|
||||
Boolean getStripVersionsFromReferences();
|
||||
|
||||
/**
|
||||
* Is the parser in "summary mode"? See {@link #setSummaryMode(boolean)} for information
|
||||
|
@ -301,21 +305,22 @@ public interface IParser {
|
|||
IParser setParserErrorHandler(IParserErrorHandler theErrorHandler);
|
||||
|
||||
/**
|
||||
* If set, when parsing resources the parser will try to use the given types when possible, in
|
||||
* 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
|
||||
* 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
|
||||
* 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>
|
||||
* in the metadata statement.
|
||||
* </p>
|
||||
*
|
||||
* @param thePreferTypes The preferred types, or <code>null</code>
|
||||
* @param thePreferTypes
|
||||
* The preferred types, or <code>null</code>
|
||||
*/
|
||||
void setPreferTypes(List<Class<? extends IBaseResource>> thePreferTypes);
|
||||
|
||||
|
@ -345,13 +350,17 @@ public interface IParser {
|
|||
* in most situations, references from one resource to another should be to the resource by ID, not
|
||||
* by ID and version. In some cases though, it may be desirable to preserve the version in resource
|
||||
* links. In that case, this value should be set to <code>false</code>.
|
||||
*
|
||||
* <p>
|
||||
* This method provides the ability to globally disable reference encoding. If finer-grained
|
||||
* control is needed, use {@link #setDontStripVersionsFromReferencesAtPaths(String...)}
|
||||
* </p>
|
||||
* @param theStripVersionsFromReferences
|
||||
* Set this to <code>false<code> to prevent the parser from removing
|
||||
* resource versions from references.
|
||||
* Set this to <code>false<code> to prevent the parser from removing resource versions from references (or <code>null</code> to apply the default setting from the {@link ParserOptions}
|
||||
* @see #setDontStripVersionsFromReferencesAtPaths(String...)
|
||||
* @see ParserOptions
|
||||
* @return Returns a reference to <code>this</code> parser so that method calls can be chained together
|
||||
*/
|
||||
IParser setStripVersionsFromReferences(boolean theStripVersionsFromReferences);
|
||||
IParser setStripVersionsFromReferences(Boolean theStripVersionsFromReferences);
|
||||
|
||||
/**
|
||||
* If set to <code>true</code> (default is <code>false</code>) only elements marked by the FHIR specification as
|
||||
|
@ -366,4 +375,60 @@ public interface IParser {
|
|||
* values.
|
||||
*/
|
||||
IParser setSuppressNarratives(boolean theSuppressNarratives);
|
||||
|
||||
/**
|
||||
* If supplied value(s), any resource references at the specified paths will have their
|
||||
* resource versions encoded instead of being automatically stripped during the encoding
|
||||
* process. This setting has no effect on the parsing process.
|
||||
* <p>
|
||||
* This method provides a finer-grained level of control than {@link #setStripVersionsFromReferences(Boolean)}
|
||||
* and any paths specified by this method will be encoded even if {@link #setStripVersionsFromReferences(Boolean)}
|
||||
* has been set to <code>true</code> (which is the default)
|
||||
* </p>
|
||||
*
|
||||
* @param thePaths
|
||||
* A collection of paths for which the resource versions will not be removed automatically
|
||||
* when serializing, e.g. "Patient.managingOrganization" or "AuditEvent.object.reference". Note that
|
||||
* only resource name and field names with dots separating is allowed here (no repetition
|
||||
* indicators, FluentPath expressions, etc.). Set to <code>null</code> to use the value
|
||||
* set in the {@link ParserOptions}
|
||||
* @see #setStripVersionsFromReferences(Boolean)
|
||||
* @see ParserOptions
|
||||
* @return Returns a reference to <code>this</code> parser so that method calls can be chained together
|
||||
*/
|
||||
IParser setDontStripVersionsFromReferencesAtPaths(String... thePaths);
|
||||
|
||||
/**
|
||||
* If supplied value(s), any resource references at the specified paths will have their
|
||||
* resource versions encoded instead of being automatically stripped during the encoding
|
||||
* process. This setting has no effect on the parsing process.
|
||||
* <p>
|
||||
* This method provides a finer-grained level of control than {@link #setStripVersionsFromReferences(Boolean)}
|
||||
* and any paths specified by this method will be encoded even if {@link #setStripVersionsFromReferences(Boolean)}
|
||||
* has been set to <code>true</code> (which is the default)
|
||||
* </p>
|
||||
*
|
||||
* @param thePaths
|
||||
* A collection of paths for which the resource versions will not be removed automatically
|
||||
* when serializing, e.g. "Patient.managingOrganization" or "AuditEvent.object.reference". Note that
|
||||
* only resource name and field names with dots separating is allowed here (no repetition
|
||||
* indicators, FluentPath expressions, etc.). Set to <code>null</code> to use the value
|
||||
* set in the {@link ParserOptions}
|
||||
* @see #setStripVersionsFromReferences(Boolean)
|
||||
* @see ParserOptions
|
||||
* @return Returns a reference to <code>this</code> parser so that method calls can be chained together
|
||||
*/
|
||||
IParser setDontStripVersionsFromReferencesAtPaths(Collection<String> thePaths);
|
||||
|
||||
/**
|
||||
* Returns the value supplied to {@link IParser#setDontStripVersionsFromReferencesAtPaths(String...)}
|
||||
* or <code>null</code> if no value has been set for this parser (in which case the default from
|
||||
* the {@link ParserOptions} will be used}
|
||||
*
|
||||
* @see #setDontStripVersionsFromReferencesAtPaths(String...)
|
||||
* @see #setStripVersionsFromReferences(Boolean)
|
||||
* @see ParserOptions
|
||||
*/
|
||||
Set<String> getDontStripVersionsFromReferencesAtPaths();
|
||||
|
||||
}
|
||||
|
|
|
@ -152,7 +152,7 @@ public class JsonParser extends BaseParser implements IParser {
|
|||
}
|
||||
}
|
||||
|
||||
private boolean addToHeldExtensions(int valueIdx, List<? extends IBaseExtension<?, ?>> ext, ArrayList<ArrayList<HeldExtension>> list, boolean theIsModifier) {
|
||||
private boolean addToHeldExtensions(int valueIdx, List<? extends IBaseExtension<?, ?>> ext, ArrayList<ArrayList<HeldExtension>> list, boolean theIsModifier, CompositeChildElement theChildElem) {
|
||||
if (ext.size() > 0) {
|
||||
list.ensureCapacity(valueIdx);
|
||||
while (list.size() <= valueIdx) {
|
||||
|
@ -162,7 +162,7 @@ public class JsonParser extends BaseParser implements IParser {
|
|||
list.set(valueIdx, new ArrayList<JsonParser.HeldExtension>());
|
||||
}
|
||||
for (IBaseExtension<?, ?> next : ext) {
|
||||
list.get(valueIdx).add(new HeldExtension(next, theIsModifier));
|
||||
list.get(valueIdx).add(new HeldExtension(next, theIsModifier, theChildElem));
|
||||
}
|
||||
return true;
|
||||
} else {
|
||||
|
@ -593,7 +593,7 @@ public class JsonParser extends BaseParser implements IParser {
|
|||
|
||||
if (nextChildElem.getDef().getElementName().equals("extension") || nextChildElem.getDef().getElementName().equals("modifierExtension") || nextChild instanceof RuntimeChildDeclaredExtensionDefinition) {
|
||||
if (!haveWrittenExtensions) {
|
||||
extractAndWriteExtensionsAsDirectChild(theElement, theEventWriter, myContext.getElementDefinition(theElement.getClass()), theResDef, theResource);
|
||||
extractAndWriteExtensionsAsDirectChild(theElement, theEventWriter, myContext.getElementDefinition(theElement.getClass()), theResDef, theResource, nextChildElem);
|
||||
haveWrittenExtensions = true;
|
||||
}
|
||||
continue;
|
||||
|
@ -629,7 +629,7 @@ public class JsonParser extends BaseParser implements IParser {
|
|||
}
|
||||
|
||||
List<? extends IBase> values = nextChild.getAccessor().getValues(theElement);
|
||||
values = super.preProcessValues(nextChild, theResource, values);
|
||||
values = super.preProcessValues(nextChild, theResource, values, nextChildElem);
|
||||
|
||||
if (values == null || values.isEmpty()) {
|
||||
continue;
|
||||
|
@ -673,20 +673,20 @@ public class JsonParser extends BaseParser implements IParser {
|
|||
if (primitive) {
|
||||
if (nextValue instanceof ISupportsUndeclaredExtensions) {
|
||||
List<ExtensionDt> ext = ((ISupportsUndeclaredExtensions) nextValue).getUndeclaredExtensions();
|
||||
force |= addToHeldExtensions(valueIdx, ext, extensions, false);
|
||||
force |= addToHeldExtensions(valueIdx, ext, extensions, false, nextChildElem);
|
||||
|
||||
ext = ((ISupportsUndeclaredExtensions) nextValue).getUndeclaredModifierExtensions();
|
||||
force |= addToHeldExtensions(valueIdx, ext, modifierExtensions, true);
|
||||
force |= addToHeldExtensions(valueIdx, ext, modifierExtensions, true, nextChildElem);
|
||||
} else {
|
||||
if (nextValue instanceof IBaseHasExtensions) {
|
||||
IBaseHasExtensions element = (IBaseHasExtensions) nextValue;
|
||||
List<? extends IBaseExtension<?, ?>> ext = element.getExtension();
|
||||
force |= addToHeldExtensions(valueIdx, ext, extensions, false);
|
||||
force |= addToHeldExtensions(valueIdx, ext, extensions, false, nextChildElem);
|
||||
}
|
||||
if (nextValue instanceof IBaseHasModifierExtensions) {
|
||||
IBaseHasModifierExtensions element = (IBaseHasModifierExtensions) nextValue;
|
||||
List<? extends IBaseExtension<?, ?>> ext = element.getModifierExtension();
|
||||
force |= addToHeldExtensions(valueIdx, ext, extensions, true);
|
||||
force |= addToHeldExtensions(valueIdx, ext, extensions, true, nextChildElem);
|
||||
}
|
||||
}
|
||||
if (nextValue.hasFormatComment()) {
|
||||
|
@ -984,31 +984,32 @@ public class JsonParser extends BaseParser implements IParser {
|
|||
/**
|
||||
* This is useful only for the two cases where extensions are encoded as direct children (e.g. not in some object
|
||||
* called _name): resource extensions, and extension extensions
|
||||
* @param theChildElem
|
||||
*/
|
||||
private void extractAndWriteExtensionsAsDirectChild(IBase theElement, JsonWriter theEventWriter, BaseRuntimeElementDefinition<?> theElementDef, RuntimeResourceDefinition theResDef, IBaseResource theResource) throws IOException {
|
||||
private void extractAndWriteExtensionsAsDirectChild(IBase theElement, JsonWriter theEventWriter, BaseRuntimeElementDefinition<?> theElementDef, RuntimeResourceDefinition theResDef, IBaseResource theResource, CompositeChildElement theChildElem) throws IOException {
|
||||
List<HeldExtension> extensions = new ArrayList<HeldExtension>(0);
|
||||
List<HeldExtension> modifierExtensions = new ArrayList<HeldExtension>(0);
|
||||
|
||||
// Undeclared extensions
|
||||
extractUndeclaredExtensions(theElement, extensions, modifierExtensions);
|
||||
extractUndeclaredExtensions(theElement, extensions, modifierExtensions, theChildElem);
|
||||
|
||||
// Declared extensions
|
||||
if (theElementDef != null) {
|
||||
extractDeclaredExtensions(theElement, theElementDef, extensions, modifierExtensions);
|
||||
extractDeclaredExtensions(theElement, theElementDef, extensions, modifierExtensions, theChildElem);
|
||||
}
|
||||
|
||||
// Write the extensions
|
||||
writeExtensionsAsDirectChild(theResource, theEventWriter, theResDef, extensions, modifierExtensions);
|
||||
}
|
||||
|
||||
private void extractDeclaredExtensions(IBase theResource, BaseRuntimeElementDefinition<?> resDef, List<HeldExtension> extensions, List<HeldExtension> modifierExtensions) {
|
||||
private void extractDeclaredExtensions(IBase theResource, BaseRuntimeElementDefinition<?> resDef, List<HeldExtension> extensions, List<HeldExtension> modifierExtensions, CompositeChildElement theChildElem) {
|
||||
for (RuntimeChildDeclaredExtensionDefinition nextDef : resDef.getExtensionsNonModifier()) {
|
||||
for (IBase nextValue : nextDef.getAccessor().getValues(theResource)) {
|
||||
if (nextValue != null) {
|
||||
if (nextValue == null || nextValue.isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
extensions.add(new HeldExtension(nextDef, nextValue));
|
||||
extensions.add(new HeldExtension(nextDef, nextValue, theChildElem));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1018,13 +1019,13 @@ public class JsonParser extends BaseParser implements IParser {
|
|||
if (nextValue == null || nextValue.isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
modifierExtensions.add(new HeldExtension(nextDef, nextValue));
|
||||
modifierExtensions.add(new HeldExtension(nextDef, nextValue, theChildElem));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void extractUndeclaredExtensions(IBase theElement, List<HeldExtension> extensions, List<HeldExtension> modifierExtensions) {
|
||||
private void extractUndeclaredExtensions(IBase theElement, List<HeldExtension> extensions, List<HeldExtension> modifierExtensions, CompositeChildElement theChildElem) {
|
||||
if (theElement instanceof ISupportsUndeclaredExtensions) {
|
||||
ISupportsUndeclaredExtensions element = (ISupportsUndeclaredExtensions) theElement;
|
||||
List<ExtensionDt> ext = element.getUndeclaredExtensions();
|
||||
|
@ -1032,7 +1033,7 @@ public class JsonParser extends BaseParser implements IParser {
|
|||
if (next == null || next.isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
extensions.add(new HeldExtension(next, false));
|
||||
extensions.add(new HeldExtension(next, false, theChildElem));
|
||||
}
|
||||
|
||||
ext = element.getUndeclaredModifierExtensions();
|
||||
|
@ -1040,7 +1041,7 @@ public class JsonParser extends BaseParser implements IParser {
|
|||
if (next == null || next.isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
modifierExtensions.add(new HeldExtension(next, true));
|
||||
modifierExtensions.add(new HeldExtension(next, true, theChildElem));
|
||||
}
|
||||
} else {
|
||||
if (theElement instanceof IBaseHasExtensions) {
|
||||
|
@ -1050,7 +1051,7 @@ public class JsonParser extends BaseParser implements IParser {
|
|||
if (next == null || (ElementUtil.isEmpty(next.getValue()) && next.getExtension().isEmpty())) {
|
||||
continue;
|
||||
}
|
||||
extensions.add(new HeldExtension(next, false));
|
||||
extensions.add(new HeldExtension(next, false, theChildElem));
|
||||
}
|
||||
}
|
||||
if (theElement instanceof IBaseHasModifierExtensions) {
|
||||
|
@ -1060,7 +1061,7 @@ public class JsonParser extends BaseParser implements IParser {
|
|||
if (next == null || next.isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
modifierExtensions.add(new HeldExtension(next, true));
|
||||
modifierExtensions.add(new HeldExtension(next, true, theChildElem));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1591,18 +1592,21 @@ public class JsonParser extends BaseParser implements IParser {
|
|||
private boolean myModifier;
|
||||
private IBaseExtension<?, ?> myUndeclaredExtension;
|
||||
private IBase myValue;
|
||||
private CompositeChildElement myChildElem;
|
||||
|
||||
public HeldExtension(IBaseExtension<?, ?> theUndeclaredExtension, boolean theModifier) {
|
||||
public HeldExtension(IBaseExtension<?, ?> theUndeclaredExtension, boolean theModifier, CompositeChildElement theChildElem) {
|
||||
assert theUndeclaredExtension != null;
|
||||
myUndeclaredExtension = theUndeclaredExtension;
|
||||
myModifier = theModifier;
|
||||
myChildElem = theChildElem;
|
||||
}
|
||||
|
||||
public HeldExtension(RuntimeChildDeclaredExtensionDefinition theDef, IBase theValue) {
|
||||
public HeldExtension(RuntimeChildDeclaredExtensionDefinition theDef, IBase theValue, CompositeChildElement theChildElem) {
|
||||
assert theDef != null;
|
||||
assert theValue != null;
|
||||
myDef = theDef;
|
||||
myValue = theValue;
|
||||
myChildElem = theChildElem;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -1626,7 +1630,7 @@ public class JsonParser extends BaseParser implements IParser {
|
|||
|
||||
BaseRuntimeElementDefinition<?> def = myDef.getChildElementDefinitionByDatatype(myValue.getClass());
|
||||
if (def.getChildType() == ChildTypeEnum.RESOURCE_BLOCK) {
|
||||
extractAndWriteExtensionsAsDirectChild(myValue, theEventWriter, def, theResDef, theResource);
|
||||
extractAndWriteExtensionsAsDirectChild(myValue, theEventWriter, def, theResDef, theResource, myChildElem);
|
||||
} else {
|
||||
String childName = myDef.getChildNameByDatatype(myValue.getClass());
|
||||
encodeChildElementToStreamWriter(theResDef, theResource, theEventWriter, myValue, def, childName, false, null, false);
|
||||
|
@ -1673,7 +1677,7 @@ public class JsonParser extends BaseParser implements IParser {
|
|||
* Pre-process value - This is called in case the value is a reference
|
||||
* since we might modify the text
|
||||
*/
|
||||
value = JsonParser.super.preProcessValues(myDef, theResource, Collections.singletonList(value)).get(0);
|
||||
value = JsonParser.super.preProcessValues(myDef, theResource, Collections.singletonList(value), myChildElem).get(0);
|
||||
|
||||
RuntimeChildUndeclaredExtensionDefinition extDef = myContext.getRuntimeChildUndeclaredExtensionDefinition();
|
||||
String childName = extDef.getChildNameByDatatype(value.getClass());
|
||||
|
|
|
@ -632,7 +632,7 @@ public class XmlParser extends BaseParser implements IParser {
|
|||
} else {
|
||||
|
||||
List<? extends IBase> values = nextChild.getAccessor().getValues(theElement);
|
||||
values = super.preProcessValues(nextChild, theResource, values);
|
||||
values = super.preProcessValues(nextChild, theResource, values, nextChildElem);
|
||||
|
||||
if (values == null || values.isEmpty()) {
|
||||
continue;
|
||||
|
|
|
@ -26,6 +26,8 @@ import java.util.Arrays;
|
|||
import java.util.Locale;
|
||||
import java.util.TimeZone;
|
||||
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
|
||||
public class TestUtil {
|
||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(TestUtil.class);
|
||||
|
||||
|
@ -63,6 +65,11 @@ public class TestUtil {
|
|||
throw new Error(e);
|
||||
}
|
||||
}
|
||||
if (Modifier.isFinal(next.getModifiers())) {
|
||||
if (next.getType().equals(FhirContext.class)) {
|
||||
throw new Error("Test has final field of type FhirContext: " + next);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -39,6 +39,7 @@ import org.springframework.scheduling.concurrent.ScheduledExecutorFactoryBean;
|
|||
import org.springframework.scheduling.config.ScheduledTaskRegistrar;
|
||||
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.context.ParserOptions;
|
||||
import ca.uhn.fhir.jpa.search.DatabaseBackedPagingProvider;
|
||||
import ca.uhn.fhir.jpa.search.StaleSearchDeletingSvc;
|
||||
import ca.uhn.fhir.jpa.term.BaseHapiTerminologySvc;
|
||||
|
@ -102,6 +103,10 @@ public class BaseConfig implements SchedulingConfigurer {
|
|||
public FhirContext fhirContextDstu3() {
|
||||
if (ourFhirContextDstu3 == null) {
|
||||
ourFhirContextDstu3 = FhirContext.forDstu3();
|
||||
|
||||
// Don't strip versions in some places
|
||||
ParserOptions parserOptions = ourFhirContextDstu3.getParserOptions();
|
||||
parserOptions.setDontStripVersionsFromReferencesAtPaths("AuditEvent.entity.reference");
|
||||
}
|
||||
return ourFhirContextDstu3;
|
||||
}
|
||||
|
|
|
@ -41,6 +41,7 @@ import org.apache.http.client.methods.HttpPost;
|
|||
import org.apache.http.client.methods.HttpPut;
|
||||
import org.apache.http.entity.ContentType;
|
||||
import org.apache.http.entity.StringEntity;
|
||||
import org.hl7.fhir.dstu3.model.AuditEvent;
|
||||
import org.hl7.fhir.dstu3.model.BaseResource;
|
||||
import org.hl7.fhir.dstu3.model.Bundle;
|
||||
import org.hl7.fhir.dstu3.model.Bundle.BundleEntryComponent;
|
||||
|
@ -438,6 +439,34 @@ public class ResourceProviderDstu3Test extends BaseResourceProviderDstu3Test {
|
|||
assertEquals(output1.getId().getIdPart(), output2.getId().getIdPart());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPreserveVersionsOnAuditEvent() {
|
||||
Organization org = new Organization();
|
||||
org.setName("ORG");
|
||||
IIdType orgId = ourClient.create().resource(org).execute().getId();
|
||||
assertEquals("1", orgId.getVersionIdPart());
|
||||
|
||||
Patient patient = new Patient();
|
||||
patient.addIdentifier().setSystem("http://uhn.ca/mrns").setValue("100");
|
||||
patient.getManagingOrganization().setReference(orgId.toUnqualified().getValue());
|
||||
IIdType patientId = ourClient.create().resource(patient).execute().getId();
|
||||
assertEquals("1", patientId.getVersionIdPart());
|
||||
|
||||
AuditEvent ae = new org.hl7.fhir.dstu3.model.AuditEvent();
|
||||
ae.addEntity().getReference().setReference(patientId.toUnqualified().getValue());
|
||||
IIdType aeId = ourClient.create().resource(ae).execute().getId();
|
||||
assertEquals("1", aeId.getVersionIdPart());
|
||||
|
||||
patient = ourClient.read().resource(Patient.class).withId(patientId).execute();
|
||||
assertTrue(patient.getManagingOrganization().getReferenceElement().hasIdPart());
|
||||
assertFalse(patient.getManagingOrganization().getReferenceElement().hasVersionIdPart());
|
||||
|
||||
ae = ourClient.read().resource(AuditEvent.class).withId(aeId).execute();
|
||||
assertTrue(ae.getEntityFirstRep().getReference().getReferenceElement().hasIdPart());
|
||||
assertTrue(ae.getEntityFirstRep().getReference().getReferenceElement().hasVersionIdPart());
|
||||
|
||||
}
|
||||
|
||||
// private void delete(String theResourceType, String theParamName, String theParamValue) {
|
||||
// Bundle resources;
|
||||
// do {
|
||||
|
|
|
@ -2,6 +2,7 @@ package ca.uhn.fhir.parser;
|
|||
|
||||
import static org.hamcrest.Matchers.contains;
|
||||
import static org.hamcrest.Matchers.containsString;
|
||||
import static org.hamcrest.Matchers.empty;
|
||||
import static org.hamcrest.Matchers.not;
|
||||
import static org.hamcrest.Matchers.stringContainsInOrder;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
@ -9,6 +10,7 @@ import static org.junit.Assert.assertNotNull;
|
|||
import static org.junit.Assert.assertNull;
|
||||
import static org.junit.Assert.assertSame;
|
||||
import static org.junit.Assert.assertThat;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
import java.io.IOException;
|
||||
|
@ -25,6 +27,7 @@ import org.hamcrest.core.StringContains;
|
|||
import org.hl7.fhir.dstu3.model.Address.AddressUse;
|
||||
import org.hl7.fhir.dstu3.model.Address.AddressUseEnumFactory;
|
||||
import org.hl7.fhir.dstu3.model.Attachment;
|
||||
import org.hl7.fhir.dstu3.model.AuditEvent;
|
||||
import org.hl7.fhir.dstu3.model.Binary;
|
||||
import org.hl7.fhir.dstu3.model.Bundle;
|
||||
import org.hl7.fhir.dstu3.model.Bundle.BundleEntryComponent;
|
||||
|
@ -35,15 +38,14 @@ import org.hl7.fhir.dstu3.model.Condition;
|
|||
import org.hl7.fhir.dstu3.model.Condition.ConditionVerificationStatus;
|
||||
import org.hl7.fhir.dstu3.model.Conformance;
|
||||
import org.hl7.fhir.dstu3.model.Conformance.UnknownContentCode;
|
||||
import org.hl7.fhir.dstu3.model.Coverage;
|
||||
import org.hl7.fhir.dstu3.model.DateTimeType;
|
||||
import org.hl7.fhir.dstu3.model.DateType;
|
||||
import org.hl7.fhir.dstu3.model.DecimalType;
|
||||
import org.hl7.fhir.dstu3.model.DiagnosticReport;
|
||||
import org.hl7.fhir.dstu3.model.EnumFactory;
|
||||
import org.hl7.fhir.dstu3.model.Enumeration;
|
||||
import org.hl7.fhir.dstu3.model.ExplanationOfBenefit;
|
||||
import org.hl7.fhir.dstu3.model.Enumerations.AdministrativeGender;
|
||||
import org.hl7.fhir.dstu3.model.ExplanationOfBenefit;
|
||||
import org.hl7.fhir.dstu3.model.Extension;
|
||||
import org.hl7.fhir.dstu3.model.HumanName;
|
||||
import org.hl7.fhir.dstu3.model.IdType;
|
||||
|
@ -62,7 +64,6 @@ import org.hl7.fhir.dstu3.model.Reference;
|
|||
import org.hl7.fhir.dstu3.model.SampledData;
|
||||
import org.hl7.fhir.dstu3.model.SimpleQuantity;
|
||||
import org.hl7.fhir.dstu3.model.StringType;
|
||||
import org.hl7.fhir.dstu3.model.Type;
|
||||
import org.hl7.fhir.dstu3.model.UriType;
|
||||
import org.hl7.fhir.utilities.xhtml.XhtmlNode;
|
||||
import org.junit.After;
|
||||
|
@ -83,7 +84,7 @@ import net.sf.json.JSONSerializer;
|
|||
import net.sf.json.JsonConfig;
|
||||
|
||||
public class JsonParserDstu3Test {
|
||||
private static final FhirContext ourCtx = FhirContext.forDstu3();
|
||||
private static FhirContext ourCtx = FhirContext.forDstu3();
|
||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(JsonParserDstu3Test.class);
|
||||
|
||||
@After
|
||||
|
@ -795,6 +796,151 @@ public class JsonParserDstu3Test {
|
|||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEncodeHistoryStripVersionsFromReferences() {
|
||||
ourCtx = FhirContext.forDstu3();
|
||||
|
||||
assertNull(ourCtx.newJsonParser().getStripVersionsFromReferences());
|
||||
|
||||
Patient p = new Patient();
|
||||
p.setManagingOrganization(new Reference("http://foo.com/Organization/2/_history/1"));
|
||||
|
||||
IParser parser = ourCtx.newJsonParser();
|
||||
String enc = parser.setPrettyPrint(true).encodeResourceToString(p);
|
||||
ourLog.info(enc);
|
||||
assertThat(enc, containsString("\"reference\": \"http://foo.com/Organization/2\""));
|
||||
|
||||
parser.setStripVersionsFromReferences(false);
|
||||
enc = parser.setPrettyPrint(true).encodeResourceToString(p);
|
||||
ourLog.info(enc);
|
||||
assertThat(enc, containsString("\"reference\": \"http://foo.com/Organization/2/_history/1\""));
|
||||
|
||||
ourCtx = FhirContext.forDstu3();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEncodeHistoryStripVersionsFromReferencesFromContext() {
|
||||
ourCtx = FhirContext.forDstu3();
|
||||
|
||||
assertTrue(ourCtx.getParserOptions().isStripVersionsFromReferences());
|
||||
|
||||
Patient p = new Patient();
|
||||
p.setManagingOrganization(new Reference("http://foo.com/Organization/2/_history/1"));
|
||||
|
||||
IParser parser = ourCtx.newJsonParser();
|
||||
String enc = parser.setPrettyPrint(true).encodeResourceToString(p);
|
||||
ourLog.info(enc);
|
||||
assertThat(enc, containsString("\"reference\": \"http://foo.com/Organization/2\""));
|
||||
|
||||
ourCtx.getParserOptions().setStripVersionsFromReferences(false);
|
||||
enc = parser.setPrettyPrint(true).encodeResourceToString(p);
|
||||
ourLog.info(enc);
|
||||
assertThat(enc, containsString("\"reference\": \"http://foo.com/Organization/2/_history/1\""));
|
||||
|
||||
parser.setStripVersionsFromReferences(true);
|
||||
enc = parser.setPrettyPrint(true).encodeResourceToString(p);
|
||||
ourLog.info(enc);
|
||||
assertThat(enc, containsString("\"reference\": \"http://foo.com/Organization/2\""));
|
||||
|
||||
ourCtx = FhirContext.forDstu3();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEncodeHistoryEncodeVersionsAtPath1() {
|
||||
ourCtx = FhirContext.forDstu3();
|
||||
|
||||
assertNull(ourCtx.newJsonParser().getStripVersionsFromReferences());
|
||||
|
||||
Patient p = new Patient();
|
||||
p.setManagingOrganization(new Reference("http://foo.com/Organization/2/_history/1"));
|
||||
|
||||
IParser parser = ourCtx.newJsonParser();
|
||||
|
||||
parser.setDontStripVersionsFromReferencesAtPaths("Patient.managingOrganization");
|
||||
String enc = parser.setPrettyPrint(true).encodeResourceToString(p);
|
||||
ourLog.info(enc);
|
||||
assertThat(enc, containsString("\"reference\": \"http://foo.com/Organization/2/_history/1\""));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEncodeHistoryEncodeVersionsAtPath2() {
|
||||
ourCtx = FhirContext.forDstu3();
|
||||
|
||||
assertNull(ourCtx.newJsonParser().getStripVersionsFromReferences());
|
||||
assertTrue(ourCtx.getParserOptions().isStripVersionsFromReferences());
|
||||
|
||||
Patient p = new Patient();
|
||||
p.setManagingOrganization(new Reference("http://foo.com/Organization/2/_history/1"));
|
||||
|
||||
IParser parser = ourCtx.newJsonParser();
|
||||
|
||||
parser.setDontStripVersionsFromReferencesAtPaths("AuditEvent.entity.reference");
|
||||
String enc = parser.setPrettyPrint(true).encodeResourceToString(p);
|
||||
ourLog.info(enc);
|
||||
assertThat(enc, containsString("\"reference\": \"http://foo.com/Organization/2\""));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEncodeHistoryEncodeVersionsAtPathUsingOptions() {
|
||||
ourCtx = FhirContext.forDstu3();
|
||||
|
||||
assertNull(ourCtx.newJsonParser().getStripVersionsFromReferences());
|
||||
assertTrue(ourCtx.getParserOptions().isStripVersionsFromReferences());
|
||||
assertThat(ourCtx.getParserOptions().getDontStripVersionsFromReferencesAtPaths(), empty());
|
||||
|
||||
Patient p = new Patient();
|
||||
p.setManagingOrganization(new Reference("http://foo.com/Organization/2/_history/1"));
|
||||
|
||||
IParser parser = ourCtx.newJsonParser();
|
||||
|
||||
ourCtx.getParserOptions().setDontStripVersionsFromReferencesAtPaths("Patient.managingOrganization");
|
||||
String enc = parser.setPrettyPrint(true).encodeResourceToString(p);
|
||||
ourLog.info(enc);
|
||||
assertThat(enc, containsString("\"reference\": \"http://foo.com/Organization/2/_history/1\""));
|
||||
|
||||
ourCtx.getParserOptions().setDontStripVersionsFromReferencesAtPaths(Arrays.asList("Patient.managingOrganization"));
|
||||
enc = parser.setPrettyPrint(true).encodeResourceToString(p);
|
||||
ourLog.info(enc);
|
||||
assertThat(enc, containsString("\"reference\": \"http://foo.com/Organization/2/_history/1\""));
|
||||
|
||||
ourCtx.getParserOptions().setDontStripVersionsFromReferencesAtPaths(new HashSet<String>(Arrays.asList("Patient.managingOrganization")));
|
||||
enc = parser.setPrettyPrint(true).encodeResourceToString(p);
|
||||
ourLog.info(enc);
|
||||
assertThat(enc, containsString("\"reference\": \"http://foo.com/Organization/2/_history/1\""));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEncodeHistoryEncodeVersionsAtPath3() {
|
||||
ourCtx = FhirContext.forDstu3();
|
||||
|
||||
assertNull(ourCtx.newJsonParser().getStripVersionsFromReferences());
|
||||
|
||||
AuditEvent auditEvent = new AuditEvent();
|
||||
auditEvent.addEntity().setReference(new Reference("http://foo.com/Organization/2/_history/1"));
|
||||
|
||||
IParser parser = ourCtx.newJsonParser();
|
||||
|
||||
parser.setDontStripVersionsFromReferencesAtPaths("AuditEvent.entity.reference");
|
||||
String enc = parser.setPrettyPrint(true).encodeResourceToString(auditEvent);
|
||||
ourLog.info(enc);
|
||||
assertThat(enc, containsString("\"reference\": \"http://foo.com/Organization/2/_history/1\""));
|
||||
|
||||
parser.setDontStripVersionsFromReferencesAtPaths(new ArrayList<String>());
|
||||
enc = parser.setPrettyPrint(true).encodeResourceToString(auditEvent);
|
||||
ourLog.info(enc);
|
||||
assertThat(enc, containsString("\"reference\": \"http://foo.com/Organization/2\""));
|
||||
|
||||
parser.setDontStripVersionsFromReferencesAtPaths((String[])null);
|
||||
enc = parser.setPrettyPrint(true).encodeResourceToString(auditEvent);
|
||||
ourLog.info(enc);
|
||||
assertThat(enc, containsString("\"reference\": \"http://foo.com/Organization/2\""));
|
||||
|
||||
parser.setDontStripVersionsFromReferencesAtPaths((List<String>)null);
|
||||
enc = parser.setPrettyPrint(true).encodeResourceToString(auditEvent);
|
||||
ourLog.info(enc);
|
||||
assertThat(enc, containsString("\"reference\": \"http://foo.com/Organization/2\""));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEncodeExtendedInfrastructureComponent() {
|
||||
IParser parser = ourCtx.newJsonParser();
|
||||
|
|
|
@ -39,6 +39,7 @@ import org.hl7.fhir.dstu3.model.Address.AddressUseEnumFactory;
|
|||
import org.hl7.fhir.dstu3.model.AllergyIntolerance;
|
||||
import org.hl7.fhir.dstu3.model.Annotation;
|
||||
import org.hl7.fhir.dstu3.model.Appointment;
|
||||
import org.hl7.fhir.dstu3.model.AuditEvent;
|
||||
import org.hl7.fhir.dstu3.model.Binary;
|
||||
import org.hl7.fhir.dstu3.model.Bundle;
|
||||
import org.hl7.fhir.dstu3.model.Bundle.BundleEntryComponent;
|
||||
|
@ -113,13 +114,47 @@ import ca.uhn.fhir.rest.server.Constants;
|
|||
import ca.uhn.fhir.util.TestUtil;
|
||||
|
||||
public class XmlParserDstu3Test {
|
||||
private static final FhirContext ourCtx = FhirContext.forDstu3();
|
||||
private static FhirContext ourCtx = FhirContext.forDstu3();
|
||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(XmlParserDstu3Test.class);
|
||||
|
||||
@After
|
||||
public void after() {
|
||||
ourCtx.setNarrativeGenerator(null);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEncodeHistoryEncodeVersionsAtPath3() {
|
||||
ourCtx = FhirContext.forDstu3();
|
||||
|
||||
assertNull(ourCtx.newXmlParser().getStripVersionsFromReferences());
|
||||
|
||||
AuditEvent auditEvent = new AuditEvent();
|
||||
auditEvent.addEntity().setReference(new Reference("http://foo.com/Organization/2/_history/1"));
|
||||
|
||||
IParser parser = ourCtx.newXmlParser();
|
||||
|
||||
parser.setDontStripVersionsFromReferencesAtPaths("AuditEvent.entity.reference");
|
||||
String enc = parser.setPrettyPrint(true).encodeResourceToString(auditEvent);
|
||||
ourLog.info(enc);
|
||||
assertThat(enc, containsString("<reference value=\"http://foo.com/Organization/2/_history/1\"/>"));
|
||||
|
||||
parser.setDontStripVersionsFromReferencesAtPaths(new ArrayList<String>());
|
||||
enc = parser.setPrettyPrint(true).encodeResourceToString(auditEvent);
|
||||
ourLog.info(enc);
|
||||
assertThat(enc, containsString("<reference value=\"http://foo.com/Organization/2\"/>"));
|
||||
|
||||
parser.setDontStripVersionsFromReferencesAtPaths((String[])null);
|
||||
enc = parser.setPrettyPrint(true).encodeResourceToString(auditEvent);
|
||||
ourLog.info(enc);
|
||||
assertThat(enc, containsString("<reference value=\"http://foo.com/Organization/2\"/>"));
|
||||
|
||||
parser.setDontStripVersionsFromReferencesAtPaths((List<String>)null);
|
||||
enc = parser.setPrettyPrint(true).encodeResourceToString(auditEvent);
|
||||
ourLog.info(enc);
|
||||
assertThat(enc, containsString("<reference value=\"http://foo.com/Organization/2\"/>"));
|
||||
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testBundleWithBinary() {
|
||||
|
|
|
@ -78,6 +78,12 @@
|
|||
DSTU2 HL7org structures with the JAX-RS module. Thanks to Carlo Mion
|
||||
for the pull request!
|
||||
</action>
|
||||
<action type="add" issue="403">
|
||||
It is not possible to configure both the parser and the context to
|
||||
preserve versions in resource references (default behaviour is to
|
||||
strip versions from references). Thanks to GitHub user @cknaap
|
||||
for the suggestion!
|
||||
</action>
|
||||
</release>
|
||||
<release version="1.6" date="2016-07-07">
|
||||
<action type="fix">
|
||||
|
|
|
@ -209,7 +209,48 @@ System.out.println(encoded);]]></source>
|
|||
|
||||
</section>
|
||||
|
||||
<section name="Versionned References">
|
||||
|
||||
<p>
|
||||
By default, HAPI will strip resource versions from references between resources.
|
||||
For example, if you set a reference to <code>Patient.managingOrganization</code>
|
||||
to the value <code>Patient/123/_history/2</code>, HAPI will encode this
|
||||
reference as <code>Patient/123</code>.
|
||||
</p>
|
||||
<p>
|
||||
This is because in most circumstances, references between resources should be
|
||||
versionless (e.g. the reference just points to the latest version, whatever
|
||||
version that might be).
|
||||
</p>
|
||||
<p>
|
||||
There are valid circumstances however for wanting versioned references. If you
|
||||
need HAPI to emit versionned references, you have a few options:
|
||||
</p>
|
||||
<p>
|
||||
You can force the parser to never strip versions:
|
||||
</p>
|
||||
<macro name="snippet">
|
||||
<param name="id" value="disableStripVersions" />
|
||||
<param name="file" value="examples/src/main/java/example/Parser.java" />
|
||||
</macro>
|
||||
<p>
|
||||
You can also disable this behaviour entirely on the context (so that it
|
||||
will apply to all parsers):
|
||||
</p>
|
||||
<macro name="snippet">
|
||||
<param name="id" value="disableStripVersionsCtx" />
|
||||
<param name="file" value="examples/src/main/java/example/Parser.java" />
|
||||
</macro>
|
||||
<p>
|
||||
You can also configure HAPI to not strip versions only on certain fields. This
|
||||
is desirable if you want versionless references in most places but need them
|
||||
in some places:
|
||||
</p>
|
||||
<macro name="snippet">
|
||||
<param name="id" value="disableStripVersionsField" />
|
||||
<param name="file" value="examples/src/main/java/example/Parser.java" />
|
||||
</macro>
|
||||
</section>
|
||||
</body>
|
||||
|
||||
</document>
|
||||
|
|
Loading…
Reference in New Issue