From 6918bb6b4b1eaa4880f88fccf9e0cc91ad007f5e Mon Sep 17 00:00:00 2001 From: "b.debeaubien" Date: Thu, 9 Apr 2015 14:06:14 -0400 Subject: [PATCH] #154 - FhirTerser now uses the complete path to a resource when creating ResourceReferenceInfo entries --- .../java/ca/uhn/fhir/parser/ParserState.java | 6 +- .../java/ca/uhn/fhir/util/FhirTerser.java | 57 ++++++----- .../java/ca/uhn/fhir/util/IModelVisitor.java | 6 +- .../uhn/fhir/util/ResourceReferenceInfo.java | 97 +++++++++++-------- .../rest/server/Dstu1BundleFactoryTest.java | 17 ++++ 5 files changed, 110 insertions(+), 73 deletions(-) diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/parser/ParserState.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/parser/ParserState.java index edce214a543..8cf297d8576 100644 --- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/parser/ParserState.java +++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/parser/ParserState.java @@ -2001,7 +2001,7 @@ class ParserState { terser.visit(myInstance, new IModelVisitor() { @Override - public void acceptElement(IBase theElement, BaseRuntimeChildDefinition theChildDefinition, BaseRuntimeElementDefinition theDefinition) { + public void acceptElement(IBase theElement, List thePathToElement, BaseRuntimeChildDefinition theChildDefinition, BaseRuntimeElementDefinition theDefinition) { if (theElement instanceof BaseResourceReferenceDt) { BaseResourceReferenceDt nextRef = (BaseResourceReferenceDt) theElement; String ref = nextRef.getReference().getValue(); @@ -2019,8 +2019,8 @@ class ParserState { } @Override - public void acceptUndeclaredExtension(ISupportsUndeclaredExtensions theContainingElement, BaseRuntimeChildDefinition theChildDefinition, BaseRuntimeElementDefinition theDefinition, ExtensionDt theNextExt) { - acceptElement(theNextExt.getValue(), null, null); + public void acceptUndeclaredExtension(ISupportsUndeclaredExtensions theContainingElement, List thePathToElement, BaseRuntimeChildDefinition theChildDefinition, BaseRuntimeElementDefinition theDefinition, ExtensionDt theNextExt) { + acceptElement(theNextExt.getValue(), null, null, null); } }); 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 823266bc205..48c468b16c8 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 @@ -39,7 +39,6 @@ import ca.uhn.fhir.context.RuntimeChildChoiceDefinition; import ca.uhn.fhir.context.RuntimeChildDirectResource; import ca.uhn.fhir.context.RuntimeResourceDefinition; import ca.uhn.fhir.model.api.ExtensionDt; -import ca.uhn.fhir.model.api.IElement; import ca.uhn.fhir.model.api.IResource; import ca.uhn.fhir.model.api.ISupportsUndeclaredExtensions; import ca.uhn.fhir.model.base.composite.BaseContainedDt; @@ -61,7 +60,7 @@ public class FhirTerser { if (theElement instanceof ISupportsUndeclaredExtensions) { ISupportsUndeclaredExtensions containingElement = (ISupportsUndeclaredExtensions) theElement; for (ExtensionDt nextExt : containingElement.getUndeclaredExtensions()) { - theCallback.acceptUndeclaredExtension(containingElement, theChildDefinition, theDefinition, nextExt); + theCallback.acceptUndeclaredExtension(containingElement, null, theChildDefinition, theDefinition, nextExt); addUndeclaredExtensions(nextExt, theDefinition, theChildDefinition, theCallback); } } @@ -87,10 +86,10 @@ public class FhirTerser { public List getAllPopulatedChildElementsOfType(IBaseResource theResource, final Class theType) { final ArrayList retVal = new ArrayList(); BaseRuntimeElementCompositeDefinition def = myContext.getResourceDefinition(theResource); - visit(theResource, null, def, new IModelVisitor() { + visit(theResource, null, null, def, new IModelVisitor() { @SuppressWarnings("unchecked") @Override - public void acceptElement(IBase theElement, BaseRuntimeChildDefinition theChildDefinition, BaseRuntimeElementDefinition theDefinition) { + public void acceptElement(IBase theElement, List thePathToElement, BaseRuntimeChildDefinition theChildDefinition, BaseRuntimeElementDefinition theDefinition) { if (theElement == null || theElement.isEmpty()) { return; } @@ -102,7 +101,7 @@ public class FhirTerser { @SuppressWarnings("unchecked") @Override - public void acceptUndeclaredExtension(ISupportsUndeclaredExtensions theContainingElement, BaseRuntimeChildDefinition theChildDefinition, BaseRuntimeElementDefinition theDefinition, + public void acceptUndeclaredExtension(ISupportsUndeclaredExtensions theContainingElement, List thePathToElement, BaseRuntimeChildDefinition theChildDefinition, BaseRuntimeElementDefinition theDefinition, ExtensionDt theNextExt) { if (theType.isAssignableFrom(theNextExt.getClass())) { retVal.add((T) theNextExt); @@ -118,36 +117,31 @@ public class FhirTerser { public List getAllResourceReferences(final IBaseResource theResource) { final ArrayList retVal = new ArrayList(); BaseRuntimeElementCompositeDefinition def = myContext.getResourceDefinition(theResource); - visit(theResource, null, def, new IModelVisitor() { + visit(theResource, null, null, def, new IModelVisitor() { @SuppressWarnings("unchecked") @Override - public void acceptElement(IBase theElement, BaseRuntimeChildDefinition theChildDefinition, BaseRuntimeElementDefinition theDefinition) { + public void acceptElement(IBase theElement, List thePathToElement, BaseRuntimeChildDefinition theChildDefinition, BaseRuntimeElementDefinition theDefinition) { if (theElement == null || theElement.isEmpty()) { return; } - String name = null; - if (theChildDefinition != null) { - name = theChildDefinition.getElementName(); - } if (BaseResourceReferenceDt.class.isAssignableFrom(theElement.getClass())) { - retVal.add(new ResourceReferenceInfo(theResource, name, (BaseResourceReferenceDt)theElement)); + retVal.add(new ResourceReferenceInfo(theResource, thePathToElement, (BaseResourceReferenceDt)theElement)); } } @SuppressWarnings("unchecked") @Override - public void acceptUndeclaredExtension(ISupportsUndeclaredExtensions theContainingElement, BaseRuntimeChildDefinition theChildDefinition, BaseRuntimeElementDefinition theDefinition, + public void acceptUndeclaredExtension(ISupportsUndeclaredExtensions theContainingElement, List thePathToElement, BaseRuntimeChildDefinition theChildDefinition, BaseRuntimeElementDefinition theDefinition, ExtensionDt theNextExt) { - String name = null; - if (theChildDefinition != null) { - name = theChildDefinition.getElementName(); - } if (theNextExt.getValue() != null && BaseResourceReferenceDt.class.isAssignableFrom(theNextExt.getValue().getClass())) { - retVal.add(new ResourceReferenceInfo(theResource, name, (BaseResourceReferenceDt)theNextExt.getValue())); + retVal.add(new ResourceReferenceInfo(theResource, thePathToElement, (BaseResourceReferenceDt)theNextExt.getValue())); } } }); - return retVal; } private BaseRuntimeChildDefinition getDefinition(BaseRuntimeElementCompositeDefinition theCurrentDef, List theSubList) { + return retVal; + } + + private BaseRuntimeChildDefinition getDefinition(BaseRuntimeElementCompositeDefinition theCurrentDef, List theSubList) { BaseRuntimeChildDefinition nextDef = theCurrentDef.getChildByNameOrThrowDataFormatException(theSubList.get(0)); if (theSubList.size() == 1) { @@ -220,8 +214,19 @@ public class FhirTerser { } - private void visit(IBase theElement, BaseRuntimeChildDefinition theChildDefinition, BaseRuntimeElementDefinition theDefinition, IModelVisitor theCallback) { - theCallback.acceptElement(theElement, theChildDefinition, theDefinition); + private List addNameToList(List theCurrentList, BaseRuntimeChildDefinition theChildDefinition) { + if (theChildDefinition == null) + return null; + if (theCurrentList== null || theCurrentList.isEmpty()) + return new ArrayList(Arrays.asList(theChildDefinition.getElementName())); + List newList = new ArrayList(theCurrentList); + newList.add(theChildDefinition.getElementName()); + return newList; + } + + private void visit(IBase theElement, List thePathToElement, BaseRuntimeChildDefinition theChildDefinition, BaseRuntimeElementDefinition theDefinition, IModelVisitor theCallback) { + List pathToElement = addNameToList(thePathToElement, theChildDefinition); + theCallback.acceptElement(theElement, pathToElement, theChildDefinition, theDefinition); addUndeclaredExtensions(theElement, theDefinition, theChildDefinition, theCallback); // if (theElement.isEmpty()) { @@ -242,7 +247,7 @@ public class FhirTerser { IResource theResource = resRefDt.getResource(); if (theResource.getId() == null || theResource.getId().isEmpty() || theResource.getId().isLocal()) { BaseRuntimeElementCompositeDefinition def = myContext.getResourceDefinition(theResource); - visit(theResource, null, def, theCallback); + visit(theResource, pathToElement, null, def, theCallback); } } break; @@ -284,9 +289,9 @@ public class FhirTerser { if (nextChild instanceof RuntimeChildDirectResource) { // Don't descend into embedded resources - theCallback.acceptElement(nextValue, nextChild, childElementDef); + theCallback.acceptElement(nextValue, null, nextChild, childElementDef); } else { - visit(nextValue, nextChild, childElementDef, theCallback); + visit(nextValue, pathToElement, nextChild, childElementDef, theCallback); } } } @@ -297,7 +302,7 @@ public class FhirTerser { BaseContainedDt value = (BaseContainedDt) theElement; for (IResource next : value.getContainedResources()) { BaseRuntimeElementCompositeDefinition def = myContext.getResourceDefinition(next); - visit(next, null, def, theCallback); + visit(next, pathToElement, null, def, theCallback); } break; } @@ -322,7 +327,7 @@ public class FhirTerser { */ public void visit(IBaseResource theResource, IModelVisitor theVisitor) { BaseRuntimeElementCompositeDefinition def = myContext.getResourceDefinition(theResource); - visit(theResource, null, def, theVisitor); + visit(theResource, null, null, def, theVisitor); } public Object getSingleValueOrNull(IBase theTarget, String thePath) { diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/util/IModelVisitor.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/util/IModelVisitor.java index f183f8ee4d4..518080aab93 100644 --- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/util/IModelVisitor.java +++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/util/IModelVisitor.java @@ -28,6 +28,8 @@ import ca.uhn.fhir.context.BaseRuntimeElementDefinition; import ca.uhn.fhir.model.api.ExtensionDt; import ca.uhn.fhir.model.api.ISupportsUndeclaredExtensions; +import java.util.List; + /** * @see FhirTerser#visit(IBaseResource, IModelVisitor) */ @@ -39,7 +41,7 @@ public interface IModelVisitor { * @param theChildDefinition May be null if this is a root element * @param theDefinition */ - void acceptElement(IBase theElement, BaseRuntimeChildDefinition theChildDefinition, BaseRuntimeElementDefinition theDefinition); + void acceptElement(IBase theElement, List thePathToElement, BaseRuntimeChildDefinition theChildDefinition, BaseRuntimeElementDefinition theDefinition); /** * @@ -48,7 +50,7 @@ public interface IModelVisitor { * @param theDefinition * @param theNextExt */ - void acceptUndeclaredExtension(ISupportsUndeclaredExtensions theContainingElement, BaseRuntimeChildDefinition theChildDefinition, BaseRuntimeElementDefinition theDefinition, ExtensionDt theNextExt); + void acceptUndeclaredExtension(ISupportsUndeclaredExtensions theContainingElement, List thePathToElement, BaseRuntimeChildDefinition theChildDefinition, BaseRuntimeElementDefinition theDefinition, ExtensionDt theNextExt); diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/util/ResourceReferenceInfo.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/util/ResourceReferenceInfo.java index 1c634d695fa..fd50f9f5a81 100644 --- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/util/ResourceReferenceInfo.java +++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/util/ResourceReferenceInfo.java @@ -28,58 +28,71 @@ import org.apache.commons.lang3.builder.ToStringBuilder; import org.apache.commons.lang3.builder.ToStringStyle; import org.hl7.fhir.instance.model.IBaseResource; +import java.util.Iterator; +import java.util.List; import java.util.Set; /** * Created by Bill de Beaubien on 2/26/2015. */ public class ResourceReferenceInfo { - private String myOwningResource; - private String myName; - private BaseResourceReferenceDt myResource; + private String myOwningResource; + private String myName; + private BaseResourceReferenceDt myResource; - public ResourceReferenceInfo(IBaseResource theOwningResource, String theName, BaseResourceReferenceDt theResource) { - myOwningResource = theOwningResource.getClass().getAnnotation(ResourceDef.class).name(); - myName = theName; - myResource = theResource; - } + public ResourceReferenceInfo(IBaseResource theOwningResource, List thePathToElement, BaseResourceReferenceDt theResource) { + myOwningResource = theOwningResource.getClass().getAnnotation(ResourceDef.class).name(); + myResource = theResource; + if (thePathToElement != null && !thePathToElement.isEmpty()) { + StringBuilder sb = new StringBuilder(); + thePathToElement.iterator(); + for (Iterator iterator = thePathToElement.iterator(); iterator.hasNext(); ) { + sb.append(iterator.next()); + if (iterator.hasNext()) + sb.append("."); + } + myName = sb.toString(); + } else { + myName = null; + } + } - @Override - public String toString() { - ToStringBuilder b = new ToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE); - b.append("name", myName); - b.append("resource", myResource.getReference()); - return b.build(); - } + @Override + public String toString() { + ToStringBuilder b = new ToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE); + b.append("name", myName); + b.append("resource", myResource.getReference()); + return b.build(); + } - public String getName() { - return myName; - } + public String getName() { + return myName; + } - public BaseResourceReferenceDt getResourceReference() { - return myResource; - } + public BaseResourceReferenceDt getResourceReference() { + return myResource; + } - public boolean matchesIncludeSet(Set theIncludes) { - if (theIncludes == null) - return false; - for (Include include : theIncludes) { - if (matchesInclude(include)) - return true; - } - return false; - } + public boolean matchesIncludeSet(Set theIncludes) { + if (theIncludes == null) + return false; + for (Include include : theIncludes) { + if (matchesInclude(include)) + return true; + } + return false; + } - public boolean matchesInclude(Include theInclude) { - if (theInclude.getValue().equals("*")) { - return true; - } - if (theInclude.getValue().indexOf(':') != -1) { - // DSTU2 style - return (theInclude.getValue().equals(myOwningResource + ':' + myName)); - } else { - // DSTU1 style - return (theInclude.getValue().equals(myOwningResource + '.' + myName)); - } - } + public boolean matchesInclude(Include theInclude) { + if (theInclude.getValue().equals("*")) { + return true; + } + if (theInclude.getValue().indexOf(':') != -1) { + // DSTU2 style + return (theInclude.getValue().equals(myOwningResource + ':' + myName)); + } else { + // DSTU1 style + return (theInclude.getValue().equals(myOwningResource + '.' + myName)); + } + } } diff --git a/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/rest/server/Dstu1BundleFactoryTest.java b/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/rest/server/Dstu1BundleFactoryTest.java index bd314628214..12d4c5897df 100644 --- a/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/rest/server/Dstu1BundleFactoryTest.java +++ b/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/rest/server/Dstu1BundleFactoryTest.java @@ -76,6 +76,23 @@ public class Dstu1BundleFactoryTest { myBundleFactory = new Dstu1BundleFactory(ourCtx); } + @Test + public void whenMedicationHasIngredients_include_shouldIncludeThem() throws Exception { + Medication medication = new Medication(); + medication.setName("Main Medication"); + medication.setId("Medication/1"); + Medication ingredientMedication = new Medication(); + ingredientMedication.setName("Ingredient"); + ingredientMedication.setId("Medication/2"); + Medication.ProductIngredient ingredient = new Medication.ProductIngredient(); + ingredient.setItem(new ResourceReferenceDt(ingredientMedication)); + medication.getProduct().getIngredient().add(ingredient); + + myResourceList = Arrays.asList(new IResource[]{medication}); + Bundle bundle = makeBundle(BundleInclusionRule.BASED_ON_INCLUDES, includes("Medication.product.ingredient.item")); + assertEquals(2, bundle.getEntries().size()); + } + @Test public void whenIncludeIsAsterisk_bundle_shouldContainAllReferencedResources() throws Exception { Bundle bundle = makeBundle(BundleInclusionRule.BASED_ON_INCLUDES, includes("*"));