Skip to content

Commit

Permalink
Even more additional work on FhirTerser.getValues(...) enhancements. …
Browse files Browse the repository at this point in the history
…Almost ready for review.
  • Loading branch information
dmuylwyk committed Oct 24, 2018
1 parent 4e414a1 commit 21a0390
Show file tree
Hide file tree
Showing 4 changed files with 681 additions and 41 deletions.
Expand Up @@ -20,10 +20,10 @@
* #L%
*/

import java.util.List;

import org.hl7.fhir.instance.model.api.IBaseDatatype;

import java.util.List;

public interface ISupportsUndeclaredExtensions extends IElement {

/**
Expand All @@ -42,7 +42,8 @@ public interface ISupportsUndeclaredExtensions extends IElement {
/**
* Returns an <b>immutable</b> 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<ExtensionDt> getAllUndeclaredExtensions();

Expand Down
183 changes: 145 additions & 38 deletions hapi-fhir-base/src/main/java/ca/uhn/fhir/util/FhirTerser.java
Expand Up @@ -58,7 +58,41 @@ private List<String> addNameToList(List<String> theCurrentList, BaseRuntimeChild
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
Expand Down Expand Up @@ -214,11 +248,11 @@ public <T> T getSingleValueOrNull(IBase theTarget, String thePath, Class<T> theW
}

private <T> List<T> getValues(BaseRuntimeElementCompositeDefinition<?> theCurrentDef, Object theCurrentObj, List<String> theSubList, Class<T> theWantedClass) {
return getValues(theCurrentDef, theCurrentObj, theSubList, theWantedClass, false);
return getValues(theCurrentDef, theCurrentObj, theSubList, theWantedClass, false, false);
}

@SuppressWarnings("unchecked")
private <T> List<T> getValues(BaseRuntimeElementCompositeDefinition<?> theCurrentDef, Object theCurrentObj, List<String> theSubList, Class<T> theWantedClass, boolean theCreate) {
private <T> List<T> getValues(BaseRuntimeElementCompositeDefinition<?> theCurrentDef, Object theCurrentObj, List<String> theSubList, Class<T> theWantedClass, boolean theCreate, boolean theAddExtension) {
String name = theSubList.get(0);
List<T> retVal = new ArrayList<>();

Expand All @@ -229,27 +263,35 @@ private <T> List<T> getValues(BaseRuntimeElementCompositeDefinition<?> theCurren
extensionUrl = extensionUrl.substring(0, endIndex);
}

// DSTU2
if (myContext.getVersion().getVersion().isOlderThan(FhirVersionEnum.DSTU3)) {
// DTSU2
final String extensionDtUrlForLambda = extensionUrl;
List<ExtensionDt> 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));
}
}

Expand All @@ -268,10 +310,13 @@ private <T> List<T> getValues(BaseRuntimeElementCompositeDefinition<?> theCurren
.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));
}
}

Expand All @@ -287,7 +332,7 @@ private <T> List<T> getValues(BaseRuntimeElementCompositeDefinition<?> theCurren
retVal = new ArrayList<>();
for (T nextElement : values) {
BaseRuntimeElementCompositeDefinition<?> nextChildDef = (BaseRuntimeElementCompositeDefinition<?>) myContext.getElementDefinition((Class<? extends IBase>) nextElement.getClass());
List<T> foundValues = getValues(nextChildDef, nextElement, theSubList.subList(1, theSubList.size()), theWantedClass, theCreate);
List<T> foundValues = getValues(nextChildDef, nextElement, theSubList.subList(1, theSubList.size()), theWantedClass, theCreate, theAddExtension);
retVal.addAll(foundValues);
}
}
Expand All @@ -302,8 +347,45 @@ private <T> List<T> getValues(BaseRuntimeElementCompositeDefinition<?> theCurren
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<ExtensionDt> 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<IBaseExtension> extensions = Collections.emptyList();

Expand All @@ -313,10 +395,13 @@ private <T> List<T> getValues(BaseRuntimeElementCompositeDefinition<?> theCurren
.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));
}
}

Expand All @@ -332,7 +417,7 @@ private <T> List<T> getValues(BaseRuntimeElementCompositeDefinition<?> theCurren
retVal = new ArrayList<>();
for (T nextElement : values) {
BaseRuntimeElementCompositeDefinition<?> nextChildDef = (BaseRuntimeElementCompositeDefinition<?>) myContext.getElementDefinition((Class<? extends IBase>) nextElement.getClass());
List<T> foundValues = getValues(nextChildDef, nextElement, theSubList.subList(1, theSubList.size()), theWantedClass, theCreate);
List<T> foundValues = getValues(nextChildDef, nextElement, theSubList.subList(1, theSubList.size()), theWantedClass, theCreate, theAddExtension);
retVal.addAll(foundValues);
}
}
Expand Down Expand Up @@ -381,7 +466,7 @@ private <T> List<T> getValues(BaseRuntimeElementCompositeDefinition<?> theCurren
} else {
for (IBase nextElement : values) {
BaseRuntimeElementCompositeDefinition<?> nextChildDef = (BaseRuntimeElementCompositeDefinition<?>) myContext.getElementDefinition(nextElement.getClass());
List<T> foundValues = getValues(nextChildDef, nextElement, theSubList.subList(1, theSubList.size()), theWantedClass, theCreate);
List<T> foundValues = getValues(nextChildDef, nextElement, theSubList.subList(1, theSubList.size()), theWantedClass, theCreate, theAddExtension);
retVal.addAll(foundValues);
}
}
Expand All @@ -392,9 +477,6 @@ private <T> List<T> getValues(BaseRuntimeElementCompositeDefinition<?> theCurren
* Returns values stored in an element identified by its path. The list of values is of
* type {@link Object}.
*
* <p>Note: this method does not support creation of null-valued modifier extensions for
* versions of FHIR prior to DSTU3.</p>
*
* @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}.
Expand All @@ -409,9 +491,6 @@ public List<Object> getValues(IBaseResource theResource, String thePath) {
* Returns values stored in an element identified by its path. The list of values is of
* type {@link Object}.
*
* <p>Note: this method does not support creation of null-valued modifier extensions for
* versions of FHIR prior to DSTU3.</p>
*
* @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 <code>true</code>, the terser will create a null-valued element where none exists.
Expand All @@ -425,10 +504,23 @@ public List<Object> getValues(IBaseResource theResource, String thePath, boolean

/**
* Returns values stored in an element identified by its path. The list of values is of
* type <code>theWantedClass</code>.
* type {@link Object}.
*
* <p>Note: this method does not support creation of null-valued modifier extensions for
* versions of FHIR prior to DSTU3.</p>
* @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 <code>true</code>, the terser will create a null-valued element where none exists.
* @param theAddExtension When set to <code>true</code>, 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<Object> getValues(IBaseResource theResource, String thePath, boolean theCreate, boolean theAddExtension) {
Class<Object> wantedClass = Object.class;

return getValues(theResource, thePath, wantedClass, theCreate, theAddExtension);
}

/**
* Returns values stored in an element identified by its path. The list of values is of
* type <code>theWantedClass</code>.
*
* @param theResource The resource instance to be accessed. Must not be null.
* @param thePath The path for the element to be accessed.
Expand All @@ -446,9 +538,6 @@ public <T> List<T> getValues(IBaseResource theResource, String thePath, Class<T>
* Returns values stored in an element identified by its path. The list of values is of
* type <code>theWantedClass</code>.
*
* <p>Note: this method does not support creation of null-valued modifier extensions for
* versions of FHIR prior to DSTU3.</p>
*
* @param theResource The resource instance to be accessed. Must not be null.
* @param thePath The path for the element to be accessed.
* @param theWantedClass The desired class to be returned in a list.
Expand All @@ -459,7 +548,25 @@ public <T> List<T> getValues(IBaseResource theResource, String thePath, Class<T>
public <T> List<T> getValues(IBaseResource theResource, String thePath, Class<T> theWantedClass, boolean theCreate) {
RuntimeResourceDefinition def = myContext.getResourceDefinition(theResource);
List<String> parts = parsePath(def, thePath);
return getValues(def, theResource, parts, theWantedClass, theCreate);
return getValues(def, theResource, parts, theWantedClass, theCreate, false);
}

/**
* Returns values stored in an element identified by its path. The list of values is of
* type <code>theWantedClass</code>.
*
* @param theResource The resource instance to be accessed. Must not be null.
* @param thePath The path for the element to be accessed.
* @param theWantedClass The desired class to be returned in a list.
* @param theCreate When set to <code>true</code>, the terser will create a null-valued element where none exists.
* @param theAddExtension When set to <code>true</code>, the terser will add a null-valued extension where one or more such extensions already exist.
* @param <T> Type declared by <code>theWantedClass</code>
* @return A list of values of type <code>theWantedClass</code>.
*/
public <T> List<T> getValues(IBaseResource theResource, String thePath, Class<T> theWantedClass, boolean theCreate, boolean theAddExtension) {
RuntimeResourceDefinition def = myContext.getResourceDefinition(theResource);
List<String> parts = parsePath(def, thePath);
return getValues(def, theResource, parts, theWantedClass, theCreate, theAddExtension);
}

private List<String> parsePath(BaseRuntimeElementCompositeDefinition<?> theElementDef, String thePath) {
Expand Down

0 comments on commit 21a0390

Please sign in to comment.