diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/model/api/ISupportsUndeclaredExtensions.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/model/api/ISupportsUndeclaredExtensions.java
index afd252ed349..ee6402578bc 100644
--- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/model/api/ISupportsUndeclaredExtensions.java
+++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/model/api/ISupportsUndeclaredExtensions.java
@@ -20,10 +20,10 @@ package ca.uhn.fhir.model.api;
* #L%
*/
-import java.util.List;
-
import org.hl7.fhir.instance.model.api.IBaseDatatype;
+import java.util.List;
+
public interface ISupportsUndeclaredExtensions extends IElement {
/**
@@ -42,7 +42,8 @@ public interface ISupportsUndeclaredExtensions extends IElement {
/**
* Returns an immutable list containing all extensions (modifier and non-modifier).
*
- * @see #getUndeclaredExtensions() To return a mutable list which may be used to remove extensions
+ * @see #getUndeclaredExtensions() To return a mutable list which may be used to remove undeclared non-modifier extensions
+ * @see #getUndeclaredModifierExtensions() To return a mutable list which may be used to remove undeclared modifier extensions
*/
List getAllUndeclaredExtensions();
diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/util/FhirTerser.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/util/FhirTerser.java
index ca32e26447c..354d52d6201 100644
--- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/util/FhirTerser.java
+++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/util/FhirTerser.java
@@ -58,7 +58,41 @@ public class FhirTerser {
newList.add(theChildDefinition.getElementName());
return newList;
}
-
+
+ private ExtensionDt createEmptyExtensionDt(IBaseExtension theBaseExtension, String theUrl) {
+ return createEmptyExtensionDt(theBaseExtension, false, theUrl);
+ }
+
+ @SuppressWarnings("unchecked")
+ private ExtensionDt createEmptyExtensionDt(IBaseExtension theBaseExtension, boolean theIsModifier, String theUrl) {
+ ExtensionDt retVal = new ExtensionDt(theIsModifier, theUrl);
+ theBaseExtension.getExtension().add(retVal);
+ return retVal;
+ }
+
+ private ExtensionDt createEmptyExtensionDt(ISupportsUndeclaredExtensions theSupportsUndeclaredExtensions, String theUrl) {
+ return createEmptyExtensionDt(theSupportsUndeclaredExtensions, false, theUrl);
+ }
+
+ private ExtensionDt createEmptyExtensionDt(ISupportsUndeclaredExtensions theSupportsUndeclaredExtensions, boolean theIsModifier, String theUrl) {
+ return theSupportsUndeclaredExtensions.addUndeclaredExtension(theIsModifier, theUrl);
+ }
+
+ private IBaseExtension createEmptyExtension(IBaseHasExtensions theBaseHasExtensions, String theUrl) {
+ return (IBaseExtension) theBaseHasExtensions.addExtension().setUrl(theUrl);
+ }
+
+ private IBaseExtension createEmptyModifierExtension(IBaseHasModifierExtensions theBaseHasModifierExtensions, String theUrl) {
+ return (IBaseExtension) theBaseHasModifierExtensions.addModifierExtension().setUrl(theUrl);
+ }
+
+ private ExtensionDt createEmptyModifierExtensionDt(IBaseExtension theBaseExtension, String theUrl) {
+ return createEmptyExtensionDt(theBaseExtension, true, theUrl);
+ }
+
+ private ExtensionDt createEmptyModifierExtensionDt(ISupportsUndeclaredExtensions theSupportsUndeclaredExtensions, String theUrl) {
+ return createEmptyExtensionDt(theSupportsUndeclaredExtensions, true, theUrl);
+ }
/**
* Clones all values from a source object into the equivalent fields in a target object
@@ -214,11 +248,11 @@ public class FhirTerser {
}
private List getValues(BaseRuntimeElementCompositeDefinition> theCurrentDef, Object theCurrentObj, List theSubList, Class theWantedClass) {
- return getValues(theCurrentDef, theCurrentObj, theSubList, theWantedClass, false);
+ return getValues(theCurrentDef, theCurrentObj, theSubList, theWantedClass, false, false);
}
@SuppressWarnings("unchecked")
- private List getValues(BaseRuntimeElementCompositeDefinition> theCurrentDef, Object theCurrentObj, List theSubList, Class theWantedClass, boolean theCreate) {
+ private List getValues(BaseRuntimeElementCompositeDefinition> theCurrentDef, Object theCurrentObj, List theSubList, Class theWantedClass, boolean theCreate, boolean theAddExtension) {
String name = theSubList.get(0);
List retVal = new ArrayList<>();
@@ -229,27 +263,35 @@ public class FhirTerser {
extensionUrl = extensionUrl.substring(0, endIndex);
}
- // DSTU2
if (myContext.getVersion().getVersion().isOlderThan(FhirVersionEnum.DSTU3)) {
+ // DTSU2
+ final String extensionDtUrlForLambda = extensionUrl;
List extensionDts = Collections.emptyList();
if (theCurrentObj instanceof ISupportsUndeclaredExtensions) {
- extensionDts = ((ISupportsUndeclaredExtensions) theCurrentObj).getUndeclaredExtensionsByUrl(extensionUrl);
+ extensionDts = ((ISupportsUndeclaredExtensions) theCurrentObj).getUndeclaredExtensions()
+ .stream()
+ .filter(t -> t.getUrl().equals(extensionDtUrlForLambda))
+ .collect(Collectors.toList());
+
+ if (theAddExtension
+ && (!(theCurrentObj instanceof IBaseExtension) || (extensionDts.isEmpty() && theSubList.size() == 1))) {
+ extensionDts.add(createEmptyExtensionDt((ISupportsUndeclaredExtensions) theCurrentObj, extensionUrl));
+ }
if (extensionDts.isEmpty() && theCreate) {
- // We assume the extension is not a modifier extension.
- extensionDts = new ArrayList<>(); // Implementation of ISupportsUndeclaredExtensions.getUndeclaredExtensionsByUrl(...) returns unmodifiable list.
- ExtensionDt extensionDt = ((ISupportsUndeclaredExtensions) theCurrentObj).addUndeclaredExtension(false, extensionUrl);
- extensionDts.add(extensionDt);
+ extensionDts.add(createEmptyExtensionDt((ISupportsUndeclaredExtensions) theCurrentObj, extensionUrl));
}
+
} else if (theCurrentObj instanceof IBaseExtension) {
extensionDts = ((IBaseExtension) theCurrentObj).getExtension();
+ if (theAddExtension
+ && (extensionDts.isEmpty() && theSubList.size() == 1)) {
+ extensionDts.add(createEmptyExtensionDt((IBaseExtension) theCurrentObj, extensionUrl));
+ }
+
if (extensionDts.isEmpty() && theCreate) {
- // We assume the extension is not a modifier extension.
- ExtensionDt extensionDt = new ExtensionDt();
- extensionDt.setUrl(extensionUrl);
- ((IBaseExtension) theCurrentObj).getExtension().add(extensionDt);
- extensionDts.add(extensionDt);
+ extensionDts.add(createEmptyExtensionDt((IBaseExtension) theCurrentObj, extensionUrl));
}
}
@@ -268,10 +310,13 @@ public class FhirTerser {
.filter(t -> t.getUrl().equals(extensionUrlForLambda))
.collect(Collectors.toList());
+ if (theAddExtension
+ && (!(theCurrentObj instanceof IBaseExtension) || (extensions.isEmpty() && theSubList.size() == 1))) {
+ extensions.add(createEmptyExtension((IBaseHasExtensions) theCurrentObj, extensionUrl));
+ }
+
if (extensions.isEmpty() && theCreate) {
- IBaseExtension extension = ((IBaseHasExtensions) theCurrentObj).addExtension();
- extension.setUrl(extensionUrl);
- extensions.add(extension);
+ extensions.add(createEmptyExtension((IBaseHasExtensions) theCurrentObj, extensionUrl));
}
}
@@ -287,7 +332,7 @@ public class FhirTerser {
retVal = new ArrayList<>();
for (T nextElement : values) {
BaseRuntimeElementCompositeDefinition> nextChildDef = (BaseRuntimeElementCompositeDefinition>) myContext.getElementDefinition((Class extends IBase>) nextElement.getClass());
- List foundValues = getValues(nextChildDef, nextElement, theSubList.subList(1, theSubList.size()), theWantedClass, theCreate);
+ List foundValues = getValues(nextChildDef, nextElement, theSubList.subList(1, theSubList.size()), theWantedClass, theCreate, theAddExtension);
retVal.addAll(foundValues);
}
}
@@ -302,8 +347,45 @@ public class FhirTerser {
extensionUrl = extensionUrl.substring(0, endIndex);
}
- // DSTU3+
- if (myContext.getVersion().getVersion().isEqualOrNewerThan(FhirVersionEnum.DSTU3)) {
+ if (myContext.getVersion().getVersion().isOlderThan(FhirVersionEnum.DSTU3)) {
+ // DSTU2
+ final String extensionDtUrlForLambda = extensionUrl;
+ List extensionDts = Collections.emptyList();
+ if (theCurrentObj instanceof ISupportsUndeclaredExtensions) {
+ extensionDts = ((ISupportsUndeclaredExtensions) theCurrentObj).getUndeclaredModifierExtensions()
+ .stream()
+ .filter(t -> t.getUrl().equals(extensionDtUrlForLambda))
+ .collect(Collectors.toList());
+
+ if (theAddExtension
+ && (!(theCurrentObj instanceof IBaseExtension) || (extensionDts.isEmpty() && theSubList.size() == 1))) {
+ extensionDts.add(createEmptyModifierExtensionDt((ISupportsUndeclaredExtensions) theCurrentObj, extensionUrl));
+ }
+
+ if (extensionDts.isEmpty() && theCreate) {
+ extensionDts.add(createEmptyModifierExtensionDt((ISupportsUndeclaredExtensions) theCurrentObj, extensionUrl));
+ }
+
+ } else if (theCurrentObj instanceof IBaseExtension) {
+ extensionDts = ((IBaseExtension) theCurrentObj).getExtension();
+
+ if (theAddExtension
+ && (extensionDts.isEmpty() && theSubList.size() == 1)) {
+ extensionDts.add(createEmptyExtensionDt((IBaseExtension) theCurrentObj, extensionUrl));
+ }
+
+ if (extensionDts.isEmpty() && theCreate) {
+ extensionDts.add(createEmptyExtensionDt((IBaseExtension) theCurrentObj, extensionUrl));
+ }
+ }
+
+ for (ExtensionDt next : extensionDts) {
+ if (theWantedClass.isAssignableFrom(next.getClass())) {
+ retVal.add((T) next);
+ }
+ }
+ } else {
+ // DSTU3+
final String extensionUrlForLambda = extensionUrl;
List extensions = Collections.emptyList();
@@ -313,10 +395,13 @@ public class FhirTerser {
.filter(t -> t.getUrl().equals(extensionUrlForLambda))
.collect(Collectors.toList());
+ if (theAddExtension
+ && (!(theCurrentObj instanceof IBaseExtension) || (extensions.isEmpty() && theSubList.size() == 1))) {
+ extensions.add(createEmptyModifierExtension((IBaseHasModifierExtensions) theCurrentObj, extensionUrl));
+ }
+
if (extensions.isEmpty() && theCreate) {
- IBaseExtension modifierExtension = ((IBaseHasModifierExtensions) theCurrentObj).addModifierExtension();
- modifierExtension.setUrl(extensionUrl);
- extensions.add(modifierExtension);
+ extensions.add(createEmptyModifierExtension((IBaseHasModifierExtensions) theCurrentObj, extensionUrl));
}
}
@@ -332,7 +417,7 @@ public class FhirTerser {
retVal = new ArrayList<>();
for (T nextElement : values) {
BaseRuntimeElementCompositeDefinition> nextChildDef = (BaseRuntimeElementCompositeDefinition>) myContext.getElementDefinition((Class extends IBase>) nextElement.getClass());
- List foundValues = getValues(nextChildDef, nextElement, theSubList.subList(1, theSubList.size()), theWantedClass, theCreate);
+ List foundValues = getValues(nextChildDef, nextElement, theSubList.subList(1, theSubList.size()), theWantedClass, theCreate, theAddExtension);
retVal.addAll(foundValues);
}
}
@@ -381,7 +466,7 @@ public class FhirTerser {
} else {
for (IBase nextElement : values) {
BaseRuntimeElementCompositeDefinition> nextChildDef = (BaseRuntimeElementCompositeDefinition>) myContext.getElementDefinition(nextElement.getClass());
- List foundValues = getValues(nextChildDef, nextElement, theSubList.subList(1, theSubList.size()), theWantedClass, theCreate);
+ List foundValues = getValues(nextChildDef, nextElement, theSubList.subList(1, theSubList.size()), theWantedClass, theCreate, theAddExtension);
retVal.addAll(foundValues);
}
}
@@ -392,9 +477,6 @@ public class FhirTerser {
* Returns values stored in an element identified by its path. The list of values is of
* type {@link Object}.
*
- *
Note: this method does not support creation of null-valued modifier extensions for
- * versions of FHIR prior to DSTU3.
- *
* @param theResource The resource instance to be accessed. Must not be null.
* @param thePath The path for the element to be accessed.
* @return A list of values of type {@link Object}.
@@ -409,9 +491,6 @@ public class FhirTerser {
* Returns values stored in an element identified by its path. The list of values is of
* type {@link Object}.
*
- *
Note: this method does not support creation of null-valued modifier extensions for
- * versions of FHIR prior to DSTU3.
- *
* @param theResource The resource instance to be accessed. Must not be null.
* @param thePath The path for the element to be accessed.
* @param theCreate When set to true, the terser will create a null-valued element where none exists.
@@ -425,10 +504,23 @@ public class FhirTerser {
/**
* Returns values stored in an element identified by its path. The list of values is of
- * type theWantedClass.
+ * type {@link Object}.
*
- *
Note: this method does not support creation of null-valued modifier extensions for
- * versions of FHIR prior to DSTU3.
+ * @param theResource The resource instance to be accessed. Must not be null.
+ * @param thePath The path for the element to be accessed.
+ * @param theCreate When set to true, the terser will create a null-valued element where none exists.
+ * @param theAddExtension When set to true, the terser will add a null-valued extension where one or more such extensions already exist.
+ * @return A list of values of type {@link Object}.
+ */
+ public List