Work on term service, and allow child classes when serializing

This commit is contained in:
jamesagnew 2016-06-29 08:08:42 -04:00
parent d7fdaf7618
commit 9b6f548970
16 changed files with 675 additions and 127 deletions

View File

@ -25,6 +25,18 @@
<artifactId>slf4j-simple</artifactId>
<version>1.7.7</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-simple</artifactId>
<version>1.7.7</version>
</dependency>
<!-- Xiaomi phones depend on an old version of this... See #394 -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.2</version><!--$NO-MVN-MAN-VER$-->
</dependency>
<!--
Woodstox note: The hapi-fhir-base-testmindeps-client project includes no Woodstox at all, so that we use the

View File

@ -27,6 +27,7 @@ import java.io.Reader;
import java.io.StringReader;
import java.io.StringWriter;
import java.io.Writer;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
@ -43,6 +44,7 @@ import org.hl7.fhir.instance.model.api.IAnyResource;
import org.hl7.fhir.instance.model.api.IBase;
import org.hl7.fhir.instance.model.api.IBaseCoding;
import org.hl7.fhir.instance.model.api.IBaseElement;
import org.hl7.fhir.instance.model.api.IBaseExtension;
import org.hl7.fhir.instance.model.api.IBaseHasExtensions;
import org.hl7.fhir.instance.model.api.IBaseHasModifierExtensions;
import org.hl7.fhir.instance.model.api.IBaseMetaType;
@ -65,7 +67,6 @@ import ca.uhn.fhir.context.RuntimeChildContainedResources;
import ca.uhn.fhir.context.RuntimeChildNarrativeDefinition;
import ca.uhn.fhir.context.RuntimeResourceDefinition;
import ca.uhn.fhir.model.api.Bundle;
import ca.uhn.fhir.model.api.BundleEntry;
import ca.uhn.fhir.model.api.IIdentifiableElement;
import ca.uhn.fhir.model.api.IResource;
import ca.uhn.fhir.model.api.ISupportsUndeclaredExtensions;
@ -81,6 +82,7 @@ public abstract class BaseParser implements IParser {
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(BaseParser.class);
private ContainedResources myContainedResources;
private FhirContext myContext;
private Set<String> myDontEncodeElements;
private boolean myDontEncodeElementsIncludesStars;
@ -95,7 +97,6 @@ public abstract class BaseParser implements IParser {
private boolean myStripVersionsFromReferences = true;
private boolean mySummaryMode;
private boolean mySuppressNarratives;
/**
* Constructor
*
@ -395,6 +396,51 @@ public abstract class BaseParser implements IParser {
return retVal;
}
@SuppressWarnings("unchecked")
ChildNameAndDef getChildNameAndDef(BaseRuntimeChildDefinition theChild, IBase theValue) {
Class<? extends IBase> type = theValue.getClass();
String childName = theChild.getChildNameByDatatype(type);
BaseRuntimeElementDefinition<?> childDef = theChild.getChildElementDefinitionByDatatype(type);
if (childDef == 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
* way..
*/
BaseRuntimeElementDefinition<?> elementDef = myContext.getElementDefinition(type);
if (elementDef.getName().equals("code")) {
Class<? extends IBase> type2 = myContext.getElementDefinition("code").getImplementingClass();
childDef = theChild.getChildElementDefinitionByDatatype(type2);
childName = theChild.getChildNameByDatatype(type2);
}
// See possibly the user has extended a built-in type without
// declaring it anywhere, as in XmlParserDstu3Test#testEncodeUndeclaredBlock
if (childDef == null) {
Class<?> nextSuperType = theValue.getClass();
while (IBase.class.isAssignableFrom(nextSuperType) && childDef == null) {
if (Modifier.isAbstract(nextSuperType.getModifiers()) == false) {
BaseRuntimeElementDefinition<?> def = myContext.getElementDefinition((Class<? extends IBase>) nextSuperType);
Class<?> nextChildType = def.getImplementingClass();
childDef = theChild.getChildElementDefinitionByDatatype((Class<? extends IBase>) nextChildType);
childName = theChild.getChildNameByDatatype((Class<? extends IBase>) nextChildType);
}
nextSuperType = nextSuperType.getSuperclass();
}
}
if (childDef == null) {
throwExceptionForUnknownChildType(theChild, type);
}
}
return new ChildNameAndDef(childName, childDef);
}
protected String getCompositeElementId(IBase theElement) {
String elementId = null;
if (!(theElement instanceof IBaseResource)) {
@ -882,6 +928,26 @@ public abstract class BaseParser implements IParser {
return false;
}
class ChildNameAndDef {
private final BaseRuntimeElementDefinition<?> myChildDef;
private final String myChildName;
public ChildNameAndDef(String theChildName, BaseRuntimeElementDefinition<?> theChildDef) {
myChildName = theChildName;
myChildDef = theChildDef;
}
public BaseRuntimeElementDefinition<?> getChildDef() {
return myChildDef;
}
public String getChildName() {
return myChildName;
}
}
protected class CompositeChildElement {
private final BaseRuntimeChildDefinition myDef;
private final CompositeChildElement myParent;

View File

@ -612,13 +612,13 @@ public class JsonParser extends BaseParser implements IParser {
}
}
Class<? extends IBase> type = nextValue.getClass();
String childName = nextChild.getChildNameByDatatype(type);
BaseRuntimeElementDefinition<?> childDef = nextChild.getChildElementDefinitionByDatatype(type);
if (childDef == null) {
super.throwExceptionForUnknownChildType(nextChild, type);
BaseParser.ChildNameAndDef childNameAndDef = super.getChildNameAndDef(nextChild, nextValue);
if (childNameAndDef == null) {
continue;
}
String childName = childNameAndDef.getChildName();
BaseRuntimeElementDefinition<?> childDef = childNameAndDef.getChildDef();
boolean primitive = childDef.getChildType() == ChildTypeEnum.PRIMITIVE_DATATYPE;
if ((childDef.getChildType() == ChildTypeEnum.CONTAINED_RESOURCES || childDef.getChildType() == ChildTypeEnum.CONTAINED_RESOURCE_LIST) && theContainedResource) {

View File

@ -236,12 +236,6 @@ public class XmlParser extends BaseParser implements IParser {
break;
}
case XMLStreamConstants.ATTRIBUTE: {
Attribute elem = (Attribute) nextEvent;
String name = (elem.getName().getLocalPart());
parserState.attributeValue(name, elem.getValue());
break;
}
case XMLStreamConstants.END_DOCUMENT:
case XMLStreamConstants.END_ELEMENT: {
if (!heldComments.isEmpty()) {
@ -649,31 +643,14 @@ public class XmlParser extends BaseParser implements IParser {
continue;
}
Class<? extends IBase> type = nextValue.getClass();
String childName = nextChild.getChildNameByDatatype(type);
String extensionUrl = nextChild.getExtensionUrl();
BaseRuntimeElementDefinition<?> childDef = nextChild.getChildElementDefinitionByDatatype(type);
if (childDef == null) {
if (nextValue instanceof IBaseExtension) {
BaseParser.ChildNameAndDef childNameAndDef = super.getChildNameAndDef(nextChild, nextValue);
if (childNameAndDef == null) {
continue;
}
/*
* For RI structures Enumeration class, this replaces the child def
* with the "code" one. This is messy, and presumably there is a better
* way..
*/
BaseRuntimeElementDefinition<?> elementDef = myContext.getElementDefinition(type);
if (elementDef.getName().equals("code")) {
Class type2 = myContext.getElementDefinition("code").getImplementingClass();
childDef = nextChild.getChildElementDefinitionByDatatype(type2);
childName = nextChild.getChildNameByDatatype(type2);
}
if (childDef == null) {
super.throwExceptionForUnknownChildType(nextChild, type);
}
}
String childName = childNameAndDef.getChildName();
BaseRuntimeElementDefinition<?> childDef = childNameAndDef.getChildDef();
String extensionUrl = nextChild.getExtensionUrl();
if (nextValue instanceof IBaseExtension && myContext.getVersion().getVersion() == FhirVersionEnum.DSTU1) {
// This is called for the Query resource in DSTU1 only

View File

@ -61,6 +61,7 @@ public class XmlUtil {
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(XmlUtil.class);
private static volatile XMLOutputFactory ourOutputFactory;
private static XMLOutputFactory ourFragmentOutputFactory;
private static Throwable ourNextException;
private static final Map<String, Integer> VALID_ENTITY_NAMES;
private static final ExtendedEntityReplacingXmlResolver XML_RESOLVER = new ExtendedEntityReplacingXmlResolver();
@ -1519,6 +1520,8 @@ public class XmlUtil {
}
public static XMLEventReader createXmlReader(Reader reader) throws FactoryConfigurationError, XMLStreamException {
throwUnitTestExceptionIfConfiguredToDoSo();
XMLInputFactory inputFactory = getOrCreateInputFactory();
// Now.. create the reader and return it
@ -1526,7 +1529,19 @@ public class XmlUtil {
return er;
}
private static void throwUnitTestExceptionIfConfiguredToDoSo() throws FactoryConfigurationError, XMLStreamException {
if (ourNextException != null) {
if (ourNextException instanceof FactoryConfigurationError) {
throw ((FactoryConfigurationError)ourNextException);
} else {
throw (XMLStreamException)ourNextException;
}
}
}
public static XMLStreamWriter createXmlStreamWriter(Writer theWriter) throws FactoryConfigurationError, XMLStreamException {
throwUnitTestExceptionIfConfiguredToDoSo();
XMLOutputFactory outputFactory = getOrCreateOutputFactory();
XMLStreamWriter retVal = outputFactory.createXMLStreamWriter(theWriter);
return retVal;
@ -1720,4 +1735,11 @@ public class XmlUtil {
}
/**
* FOR UNIT TESTS ONLY - Throw this exception for the next operation
*/
static void setThrowExceptionForUnitTest(Throwable theException) {
ourNextException = theException;
}
}

View File

@ -166,7 +166,7 @@ public abstract class BaseHapiTerminologySvc implements IHapiTerminologySvc {
public List<VersionIndependentConcept> findCodesAbove(String theSystem, String theCode) {
TermCodeSystem cs = getCodeSystem(theSystem);
if (cs == null) {
return Collections.emptyList();
return findCodesAboveUsingBuiltInSystems(theSystem, theCode);
}
TermCodeSystemVersion csv = cs.getCurrentVersion();
@ -198,7 +198,7 @@ public abstract class BaseHapiTerminologySvc implements IHapiTerminologySvc {
public List<VersionIndependentConcept> findCodesBelow(String theSystem, String theCode) {
TermCodeSystem cs = getCodeSystem(theSystem);
if (cs == null) {
return Collections.emptyList();
return findCodesBelowUsingBuiltInSystems(theSystem, theCode);
}
TermCodeSystemVersion csv = cs.getCurrentVersion();
@ -207,6 +207,24 @@ public abstract class BaseHapiTerminologySvc implements IHapiTerminologySvc {
return retVal;
}
/**
* Subclasses may override
* @param theSystem The code system
* @param theCode The code
*/
protected List<VersionIndependentConcept> findCodesBelowUsingBuiltInSystems(String theSystem, String theCode) {
return Collections.emptyList();
}
/**
* Subclasses may override
* @param theSystem The code system
* @param theCode The code
*/
protected List<VersionIndependentConcept> findCodesAboveUsingBuiltInSystems(String theSystem, String theCode) {
return Collections.emptyList();
}
private TermCodeSystemVersion findCurrentCodeSystemVersionForSystem(String theCodeSystem) {
TermCodeSystem cs = getCodeSystem(theCodeSystem);
if (cs == null || cs.getCurrentVersion() == null) {

View File

@ -29,7 +29,6 @@ import java.util.List;
import java.util.Set;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.QueryWrapperFilter;
import org.hibernate.search.jpa.FullTextEntityManager;
import org.hibernate.search.jpa.FullTextQuery;
import org.hibernate.search.query.dsl.BooleanJunction;
@ -79,6 +78,9 @@ public class HapiTerminologySvcDstu3 extends BaseHapiTerminologySvc implements I
@Autowired
private ValueSetExpander myValueSetExpander;
@Autowired
private IValidationSupport myValidationSupport;
private void addCodeIfNotAlreadyAdded(String system, ValueSetExpansionComponent retVal, Set<String> addedCodes, TermConcept nextConcept) {
if (addedCodes.add(nextConcept.getCode())) {
ValueSetExpansionContainsComponent contains = retVal.addContains();
@ -88,6 +90,71 @@ public class HapiTerminologySvcDstu3 extends BaseHapiTerminologySvc implements I
}
}
@Override
protected List<VersionIndependentConcept> findCodesBelowUsingBuiltInSystems(String theSystem, String theCode) {
ArrayList<VersionIndependentConcept> retVal = new ArrayList<VersionIndependentConcept>();
CodeSystem system = myValidationSupport.fetchCodeSystem(myContext, theSystem);
if (system != null) {
findCodesBelow(system, theSystem, theCode, retVal);
}
return retVal;
}
private void findCodesBelow(CodeSystem theSystem, String theSystemString, String theCode, List<VersionIndependentConcept> theListToPopulate) {
List<ConceptDefinitionComponent> conceptList = theSystem.getConcept();
findCodesBelow(theSystemString, theCode, theListToPopulate, conceptList);
}
private void findCodesBelow(String theSystemString, String theCode, List<VersionIndependentConcept> theListToPopulate, List<ConceptDefinitionComponent> conceptList) {
for (ConceptDefinitionComponent next : conceptList) {
if (theCode.equals(next.getCode())) {
addAllChildren(theSystemString, next, theListToPopulate);
} else {
findCodesBelow(theSystemString, theCode, theListToPopulate, next.getConcept());
}
}
}
private void findCodesAbove(CodeSystem theSystem, String theSystemString, String theCode, List<VersionIndependentConcept> theListToPopulate) {
List<ConceptDefinitionComponent> conceptList = theSystem.getConcept();
for (ConceptDefinitionComponent next : conceptList) {
addTreeIfItContainsCode(theSystemString, next, theCode, theListToPopulate);
}
}
private boolean addTreeIfItContainsCode(String theSystemString, ConceptDefinitionComponent theNext, String theCode, List<VersionIndependentConcept> theListToPopulate) {
boolean foundCodeInChild = false;
for (ConceptDefinitionComponent nextChild : theNext.getConcept()) {
foundCodeInChild |= addTreeIfItContainsCode(theSystemString, nextChild, theCode, theListToPopulate);
}
if (theCode.equals(theNext.getCode()) || foundCodeInChild) {
theListToPopulate.add(new VersionIndependentConcept(theSystemString, theNext.getCode()));
return true;
}
return false;
}
private void addAllChildren(String theSystemString, ConceptDefinitionComponent theCode, List<VersionIndependentConcept> theListToPopulate) {
if (isNotBlank(theCode.getCode())) {
theListToPopulate.add(new VersionIndependentConcept(theSystemString, theCode.getCode()));
}
for (ConceptDefinitionComponent nextChild : theCode.getConcept()) {
addAllChildren(theSystemString, nextChild, theListToPopulate);
}
}
@Override
protected List<VersionIndependentConcept> findCodesAboveUsingBuiltInSystems(String theSystem, String theCode) {
ArrayList<VersionIndependentConcept> retVal = new ArrayList<VersionIndependentConcept>();
CodeSystem system = myValidationSupport.fetchCodeSystem(myContext, theSystem);
if (system != null) {
findCodesAbove(system, theSystem, theCode, retVal);
}
return retVal;
}
private void addDisplayFilterExact(QueryBuilder qb, BooleanJunction<?> bool, ConceptSetFilterComponent nextFilter) {
bool.must(qb.phrase().onField("myDisplay").sentence(nextFilter.getValue()).createQuery());
}

View File

@ -51,6 +51,7 @@ import ca.uhn.fhir.jpa.entity.TermCodeSystemVersion;
import ca.uhn.fhir.jpa.entity.TermConcept;
import ca.uhn.fhir.jpa.entity.TermConceptParentChildLink;
import ca.uhn.fhir.jpa.provider.SystemProviderDstu2Test;
import ca.uhn.fhir.jpa.term.VersionIndependentConcept;
import ca.uhn.fhir.model.dstu2.resource.Bundle;
import ca.uhn.fhir.model.dstu2.resource.Bundle.Entry;
import ca.uhn.fhir.rest.method.IRequestOperationCallback;
@ -268,4 +269,12 @@ public abstract class BaseJpaTest {
return retVal;
}
public static Set<String> toCodes(List<VersionIndependentConcept> theConcepts) {
HashSet<String> retVal = new HashSet<String>();
for (VersionIndependentConcept next : theConcepts) {
retVal.add(next.getCode());
}
return retVal;
}
}

View File

@ -12,6 +12,7 @@ import org.apache.commons.io.IOUtils;
import org.hibernate.search.jpa.FullTextEntityManager;
import org.hibernate.search.jpa.Search;
import org.hl7.fhir.dstu3.hapi.validation.IValidationSupport;
import org.hl7.fhir.dstu3.model.AllergyIntolerance;
import org.hl7.fhir.dstu3.model.Appointment;
import org.hl7.fhir.dstu3.model.AuditEvent;
import org.hl7.fhir.dstu3.model.Bundle;
@ -91,6 +92,9 @@ public abstract class BaseJpaDstu3Test extends BaseJpaTest {
private static JpaValidationSupportChainDstu3 ourJpaValidationSupportChainDstu3;
private static IFhirResourceDaoValueSet<ValueSet, Coding, CodeableConcept> ourValueSetDao;
@Autowired
@Qualifier("myAllergyIntoleranceDaoDstu3")
protected IFhirResourceDao<AllergyIntolerance> myAllergyIntoleranceDao;
@Autowired
protected ApplicationContext myAppCtx;
@Autowired

View File

@ -11,6 +11,8 @@ import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import org.hl7.fhir.dstu3.model.AllergyIntolerance;
import org.hl7.fhir.dstu3.model.AllergyIntolerance.AllergyIntoleranceStatus;
import org.hl7.fhir.dstu3.model.AuditEvent;
import org.hl7.fhir.dstu3.model.CodeSystem;
import org.hl7.fhir.dstu3.model.CodeSystem.CodeSystemContentMode;
@ -523,6 +525,92 @@ public class FhirResourceDaoDstu3TerminologyTest extends BaseJpaDstu3Test {
}
@Test
public void testSearchCodeBelowBuiltInCodesystem() {
AllergyIntolerance ai1 = new AllergyIntolerance();
ai1.setStatus(AllergyIntoleranceStatus.ACTIVE);
String id1 = myAllergyIntoleranceDao.create(ai1, mySrd).getId().toUnqualifiedVersionless().getValue();
AllergyIntolerance ai2 = new AllergyIntolerance();
ai2.setStatus(AllergyIntoleranceStatus.CONFIRMED);
String id2 = myAllergyIntoleranceDao.create(ai2, mySrd).getId().toUnqualifiedVersionless().getValue();
AllergyIntolerance ai3 = new AllergyIntolerance();
ai3.setStatus(AllergyIntoleranceStatus.INACTIVE);
String id3 = myAllergyIntoleranceDao.create(ai3, mySrd).getId().toUnqualifiedVersionless().getValue();
SearchParameterMap params;
params = new SearchParameterMap();
params.add(AllergyIntolerance.SP_STATUS, new TokenParam("http://hl7.org/fhir/allergy-intolerance-status", AllergyIntoleranceStatus.ACTIVE.toCode()));
assertThat(toUnqualifiedVersionlessIdValues(myAllergyIntoleranceDao.search(params)), containsInAnyOrder(id1));
params = new SearchParameterMap();
params.add(AllergyIntolerance.SP_STATUS, new TokenParam("http://hl7.org/fhir/allergy-intolerance-status", AllergyIntoleranceStatus.ACTIVE.toCode()).setModifier(TokenParamModifier.BELOW));
assertThat(toUnqualifiedVersionlessIdValues(myAllergyIntoleranceDao.search(params)), containsInAnyOrder(id1, id2));
params = new SearchParameterMap();
params.add(AllergyIntolerance.SP_STATUS, new TokenParam("http://hl7.org/fhir/allergy-intolerance-status", AllergyIntoleranceStatus.CONFIRMED.toCode()).setModifier(TokenParamModifier.BELOW));
assertThat(toUnqualifiedVersionlessIdValues(myAllergyIntoleranceDao.search(params)), containsInAnyOrder(id2));
params = new SearchParameterMap();
params.add(AllergyIntolerance.SP_STATUS, new TokenParam("http://hl7.org/fhir/allergy-intolerance-status", AllergyIntoleranceStatus.CONFIRMED.toCode()));
assertThat(toUnqualifiedVersionlessIdValues(myAllergyIntoleranceDao.search(params)), containsInAnyOrder(id2));
params = new SearchParameterMap();
params.add(AllergyIntolerance.SP_STATUS, new TokenParam("http://hl7.org/fhir/allergy-intolerance-status", AllergyIntoleranceStatus.ENTEREDINERROR.toCode()));
assertThat(toUnqualifiedVersionlessIdValues(myAllergyIntoleranceDao.search(params)), empty());
// Unknown code
params = new SearchParameterMap();
params.add(AllergyIntolerance.SP_STATUS, new TokenParam("http://hl7.org/fhir/allergy-intolerance-status", "fooooo"));
assertThat(toUnqualifiedVersionlessIdValues(myAllergyIntoleranceDao.search(params)), empty());
// Unknown system
params = new SearchParameterMap();
params.add(AllergyIntolerance.SP_STATUS, new TokenParam("http://hl7.org/fhir/allergy-intolerance-status222222", "fooooo"));
assertThat(toUnqualifiedVersionlessIdValues(myAllergyIntoleranceDao.search(params)), empty());
}
@Test
@Ignore
public void testSearchCodeBelowBuiltInCodesystemUnqualified() {
AllergyIntolerance ai1 = new AllergyIntolerance();
ai1.setStatus(AllergyIntoleranceStatus.ACTIVE);
String id1 = myAllergyIntoleranceDao.create(ai1, mySrd).getId().toUnqualifiedVersionless().getValue();
AllergyIntolerance ai2 = new AllergyIntolerance();
ai2.setStatus(AllergyIntoleranceStatus.CONFIRMED);
String id2 = myAllergyIntoleranceDao.create(ai2, mySrd).getId().toUnqualifiedVersionless().getValue();
AllergyIntolerance ai3 = new AllergyIntolerance();
ai3.setStatus(AllergyIntoleranceStatus.INACTIVE);
String id3 = myAllergyIntoleranceDao.create(ai3, mySrd).getId().toUnqualifiedVersionless().getValue();
SearchParameterMap params;
params = new SearchParameterMap();
params.add(AllergyIntolerance.SP_STATUS, new TokenParam(null, AllergyIntoleranceStatus.ACTIVE.toCode()));
assertThat(toUnqualifiedVersionlessIdValues(myAllergyIntoleranceDao.search(params)), containsInAnyOrder(id1));
params = new SearchParameterMap();
params.add(AllergyIntolerance.SP_STATUS, new TokenParam(null, AllergyIntoleranceStatus.ACTIVE.toCode()).setModifier(TokenParamModifier.BELOW));
assertThat(toUnqualifiedVersionlessIdValues(myAllergyIntoleranceDao.search(params)), containsInAnyOrder(id1, id2));
params = new SearchParameterMap();
params.add(AllergyIntolerance.SP_STATUS, new TokenParam(null, AllergyIntoleranceStatus.CONFIRMED.toCode()).setModifier(TokenParamModifier.BELOW));
assertThat(toUnqualifiedVersionlessIdValues(myAllergyIntoleranceDao.search(params)), containsInAnyOrder(id2));
params = new SearchParameterMap();
params.add(AllergyIntolerance.SP_STATUS, new TokenParam(null, AllergyIntoleranceStatus.CONFIRMED.toCode()));
assertThat(toUnqualifiedVersionlessIdValues(myAllergyIntoleranceDao.search(params)), containsInAnyOrder(id2));
params = new SearchParameterMap();
params.add(AllergyIntolerance.SP_STATUS, new TokenParam(null, AllergyIntoleranceStatus.ENTEREDINERROR.toCode()));
assertThat(toUnqualifiedVersionlessIdValues(myAllergyIntoleranceDao.search(params)), empty());
}
@Test
@Ignore
public void testSearchCodeInEmptyValueSet() {

View File

@ -8,6 +8,7 @@ import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.fail;
import java.util.List;
import java.util.Set;
import org.hl7.fhir.dstu3.model.CodeSystem;
@ -102,6 +103,53 @@ public class TerminologySvcImplTest extends BaseJpaDstu3Test {
}
@Test
public void testFindCodesBelowBuiltInCodeSystem() {
List<VersionIndependentConcept> concepts;
Set<String> codes;
concepts = myTermSvc.findCodesBelow("http://hl7.org/fhir/allergy-intolerance-status", "active");
codes = toCodes(concepts);
assertThat(codes, containsInAnyOrder("active", "confirmed", "unconfirmed"));
concepts = myTermSvc.findCodesBelow("http://hl7.org/fhir/allergy-intolerance-status", "confirmed");
codes = toCodes(concepts);
assertThat(codes, containsInAnyOrder("confirmed"));
// Unknown code
concepts = myTermSvc.findCodesBelow("http://hl7.org/fhir/allergy-intolerance-status", "FOO");
codes = toCodes(concepts);
assertThat(codes, empty());
// Unknown system
concepts = myTermSvc.findCodesBelow("http://hl7.org/fhir/allergy-intolerance-status2222", "FOO");
codes = toCodes(concepts);
assertThat(codes, empty());
}
@Test
public void testFindCodesAboveBuiltInCodeSystem() {
List<VersionIndependentConcept> concepts;
Set<String> codes;
concepts = myTermSvc.findCodesAbove("http://hl7.org/fhir/allergy-intolerance-status", "active");
codes = toCodes(concepts);
assertThat(codes, containsInAnyOrder("active"));
concepts = myTermSvc.findCodesAbove("http://hl7.org/fhir/allergy-intolerance-status", "confirmed");
codes = toCodes(concepts);
assertThat(codes, containsInAnyOrder("active", "confirmed"));
// Unknown code
concepts = myTermSvc.findCodesAbove("http://hl7.org/fhir/allergy-intolerance-status", "FOO");
codes = toCodes(concepts);
assertThat(codes, empty());
// Unknown system
concepts = myTermSvc.findCodesAbove("http://hl7.org/fhir/allergy-intolerance-status2222", "FOO");
codes = toCodes(concepts);
assertThat(codes, empty());
}
@Test
public void testReindexTerminology() {

View File

@ -0,0 +1,48 @@
package ca.uhn.fhir.parser;
import org.hl7.fhir.dstu3.exceptions.FHIRException;
import org.hl7.fhir.dstu3.model.Identifier;
import org.hl7.fhir.dstu3.model.MessageHeader;
import org.hl7.fhir.dstu3.model.MessageHeader.MessageSourceComponent;
import ca.uhn.fhir.model.api.annotation.Block;
import ca.uhn.fhir.model.api.annotation.Child;
import ca.uhn.fhir.model.api.annotation.Description;
import ca.uhn.fhir.model.api.annotation.Extension;
import ca.uhn.fhir.model.api.annotation.ResourceDef;
@ResourceDef(name = "FooMessageHeader")
public class FooMessageHeader extends MessageHeader {
private static final long serialVersionUID = 1L;
@Block()
public static class FooMessageSourceComponent extends MessageHeader.MessageSourceComponent {
private static final long serialVersionUID = 1L;
@Child(name = "ext-messageheader-application-id", type = Identifier.class, modifier = true)
@Description(shortDefinition = "Message Header Application ID")
@Extension(url = "http://foo", definedLocally = false, isModifier = false)
private Identifier messageHeaderApplicationId;
/*
* Get messageHeaderApplicationId
*/
public Identifier getMessageHeaderApplicationId() throws FHIRException {
if (messageHeaderApplicationId == null) {
messageHeaderApplicationId = new Identifier();
}
return messageHeaderApplicationId;
}
/*
* Set messageHeaderApplicationId
*/
public void setmessageHeaderApplicationId(Identifier messageHeaderApplicationId) {
this.messageHeaderApplicationId = messageHeaderApplicationId;
}
}
}

View File

@ -111,6 +111,29 @@ public class JsonParserDstu3Test {
assertThat(output, containsString("\"div\":\"<div xmlns=\\\"http://www.w3.org/1999/xhtml\\\">VALUE</div>\""));
}
@Test
public void testEncodeUndeclaredBlock() throws Exception {
FooMessageHeader.FooMessageSourceComponent source = new FooMessageHeader.FooMessageSourceComponent();
source.getMessageHeaderApplicationId().setValue("APPID");
source.setName("NAME");
FooMessageHeader header = new FooMessageHeader();
header.setSource(source);
Bundle bundle = new Bundle();
bundle.addEntry().setResource(header);
IParser p = ourCtx.newJsonParser();
p.setPrettyPrint(true);
String encode = p.encodeResourceToString(bundle);
ourLog.info(encode);
assertThat(encode, containsString("\"value\":\"APPID\""));
}
/**
* See #344
*/

View File

@ -34,6 +34,7 @@ import org.custommonkey.xmlunit.XMLUnit;
import org.hamcrest.collection.IsEmptyCollection;
import org.hamcrest.core.StringContains;
import org.hamcrest.text.StringContainsInOrder;
import org.hl7.fhir.dstu3.exceptions.FHIRException;
import org.hl7.fhir.dstu3.model.Address.AddressUse;
import org.hl7.fhir.dstu3.model.Address.AddressUseEnumFactory;
import org.hl7.fhir.dstu3.model.AllergyIntolerance;
@ -76,6 +77,7 @@ import org.hl7.fhir.dstu3.model.Location;
import org.hl7.fhir.dstu3.model.Medication;
import org.hl7.fhir.dstu3.model.MedicationOrder;
import org.hl7.fhir.dstu3.model.MedicationStatement;
import org.hl7.fhir.dstu3.model.MessageHeader.MessageSourceComponent;
import org.hl7.fhir.dstu3.model.Observation;
import org.hl7.fhir.dstu3.model.Observation.ObservationRelationshipType;
import org.hl7.fhir.dstu3.model.Observation.ObservationStatus;
@ -119,87 +121,6 @@ public class XmlParserDstu3Test {
ourCtx.setNarrativeGenerator(null);
}
/**
* Make sure whitespace is preserved for pre tags
*/
@Test
public void testEncodeDivWithPreNonPrettyPrint() {
Patient p = new Patient();
p.getText().setDivAsString("<div>\n\n<p>A P TAG</p><p><pre>line1\nline2\nline3 <b>BOLD</b></pre></p></div>");
String output = ourCtx.newXmlParser().setPrettyPrint(false).encodeResourceToString(p);
ourLog.info(output);
//@formatter:off
assertThat(output, stringContainsInOrder(
"<text><div",
"<p>A P TAG</p><p>",
"<pre>line1\nline2\nline3 <b>BOLD</b></pre>"
));
//@formatter:on
}
@Test
public void testEncodeDivWithPrePrettyPrint() {
Patient p = new Patient();
p.getText().setDivAsString("<div>\n\n<p>A P TAG</p><p><pre>line1\nline2\nline3 <b>BOLD</b></pre></p></div>");
String output = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(p);
ourLog.info(output);
//@formatter:off
assertThat(output, stringContainsInOrder(
" <text>",
" <div",
" <pre>line1\nline2\nline3 <b>BOLD</b></pre>"
));
//@formatter:on
}
@Test
public void testEncodeContainedWithNonLocalId() throws Exception {
Patient p = new Patient();
p.setId("Patient1");
p.setBirthDate(new SimpleDateFormat("yyyy-mm-dd HH:mm:ss").parse("2016-04-15 10:15:30"));
ProcedureRequest pr = new ProcedureRequest();
pr.setId("1234567");
pr.setSubject(new Reference(p));
pr.setCode(new CodeableConcept().addCoding(new Coding("breastfeeding-readiness-assessment", "Breastfeeding Readiness Assessment", "Breastfeeding Readiness Assessment")));
// pr.setReason(new StringType("Single Live Birth"));
// pr.setScheduled(new DateType(new Date()));
pr.setEncounter(new Reference("Live Birth Encounter"));
pr.setPerformer(new Reference("Charge Nurse"));
pr.setStatus(ProcedureRequest.ProcedureRequestStatus.PROPOSED);
pr.setOrderedOn(new Date());
pr.setOrderer(new Reference("CDS System"));
pr.setPriority(ProcedureRequest.ProcedureRequestPriority.ROUTINE);
GuidanceResponse.GuidanceResponseStatus status = GuidanceResponse.GuidanceResponseStatus.SUCCESS;
//@formatter:off
GuidanceResponse gr = new GuidanceResponse()
.setRequestId("123")
.setModule(new Reference("Evaluate Operation"))
.setStatus(status);
//@formatter:on
gr.addAction(new GuidanceResponse.GuidanceResponseActionComponent().setTitle("Action").setResource(new Reference(pr)));
gr.getContained().add(p);
gr.getContained().add(pr);
IParser parser = ourCtx.newXmlParser();
parser.setPrettyPrint(true);
ourLog.info(parser.encodeResourceToString(gr));
}
@Test
public void testBundleWithBinary() {
//@formatter:off
@ -231,6 +152,7 @@ public class XmlParserDstu3Test {
}
@Test
public void testContainedResourceInExtensionUndeclared() {
Patient p = new Patient();
@ -253,6 +175,7 @@ public class XmlParserDstu3Test {
assertEquals("ORG", o.getName());
}
@Test
public void testDuration() {
Encounter enc = new Encounter();
@ -1040,6 +963,85 @@ public class XmlParserDstu3Test {
}
@Test
public void testEncodeContainedWithNonLocalId() throws Exception {
Patient p = new Patient();
p.setId("Patient1");
p.setBirthDate(new SimpleDateFormat("yyyy-mm-dd HH:mm:ss").parse("2016-04-15 10:15:30"));
ProcedureRequest pr = new ProcedureRequest();
pr.setId("1234567");
pr.setSubject(new Reference(p));
pr.setCode(new CodeableConcept().addCoding(new Coding("breastfeeding-readiness-assessment", "Breastfeeding Readiness Assessment", "Breastfeeding Readiness Assessment")));
// pr.setReason(new StringType("Single Live Birth"));
// pr.setScheduled(new DateType(new Date()));
pr.setEncounter(new Reference("Live Birth Encounter"));
pr.setPerformer(new Reference("Charge Nurse"));
pr.setStatus(ProcedureRequest.ProcedureRequestStatus.PROPOSED);
pr.setOrderedOn(new Date());
pr.setOrderer(new Reference("CDS System"));
pr.setPriority(ProcedureRequest.ProcedureRequestPriority.ROUTINE);
GuidanceResponse.GuidanceResponseStatus status = GuidanceResponse.GuidanceResponseStatus.SUCCESS;
//@formatter:off
GuidanceResponse gr = new GuidanceResponse()
.setRequestId("123")
.setModule(new Reference("Evaluate Operation"))
.setStatus(status);
//@formatter:on
gr.addAction(new GuidanceResponse.GuidanceResponseActionComponent().setTitle("Action").setResource(new Reference(pr)));
gr.getContained().add(p);
gr.getContained().add(pr);
IParser parser = ourCtx.newXmlParser();
parser.setPrettyPrint(true);
ourLog.info(parser.encodeResourceToString(gr));
}
/**
* Make sure whitespace is preserved for pre tags
*/
@Test
public void testEncodeDivWithPreNonPrettyPrint() {
Patient p = new Patient();
p.getText().setDivAsString("<div>\n\n<p>A P TAG</p><p><pre>line1\nline2\nline3 <b>BOLD</b></pre></p></div>");
String output = ourCtx.newXmlParser().setPrettyPrint(false).encodeResourceToString(p);
ourLog.info(output);
//@formatter:off
assertThat(output, stringContainsInOrder(
"<text><div",
"<p>A P TAG</p><p>",
"<pre>line1\nline2\nline3 <b>BOLD</b></pre>"
));
//@formatter:on
}
@Test
public void testEncodeDivWithPrePrettyPrint() {
Patient p = new Patient();
p.getText().setDivAsString("<div>\n\n<p>A P TAG</p><p><pre>line1\nline2\nline3 <b>BOLD</b></pre></p></div>");
String output = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(p);
ourLog.info(output);
//@formatter:off
assertThat(output, stringContainsInOrder(
" <text>",
" <div",
" <pre>line1\nline2\nline3 <b>BOLD</b></pre>"
));
//@formatter:on
}
@Test
public void testEncodeDoesntIncludeUuidId() {
Patient p = new Patient();
@ -1396,6 +1398,27 @@ public class XmlParserDstu3Test {
assertThat(encoded, not(containsString("maritalStatus")));
}
@Test
public void testEncodeUndeclaredBlock() throws Exception {
FooMessageHeader.FooMessageSourceComponent source = new FooMessageHeader.FooMessageSourceComponent();
source.getMessageHeaderApplicationId().setValue("APPID");
source.setName("NAME");
FooMessageHeader header = new FooMessageHeader();
header.setSource(source);
Bundle bundle = new Bundle();
bundle.addEntry().setResource(header);
IParser p = ourCtx.newXmlParser();
p.setPrettyPrint(true);
String encode = p.encodeResourceToString(bundle);
ourLog.info(encode);
assertThat(encode, containsString("<value value=\"APPID\"/>"));
}
@Test
public void testEncodeUndeclaredExtensionWithEnumerationContent() {
IParser parser = ourCtx.newXmlParser();
@ -1607,6 +1630,54 @@ public class XmlParserDstu3Test {
assertThat(output, containsString("<text><status value=\"generated\"/><div xmlns=\"http://www.w3.org/1999/xhtml\"><div class=\"hapiHeaderText\"> John <b>SMITH </b>"));
}
@Test
public void testExceptionWithoutUrl() {
//@formatter:off
String input =
"<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?>" +
"<Patient xmlns=\"http://hl7.org/fhir\">" +
"<extension>" +
"<valueString value=\"FOO\">" +
"</extension>" +
"<address>" +
"<line value=\"FOO\"/>" +
"</address>" +
"</Patient>";
//@formatter:on
try {
ourCtx.newXmlParser().parseResource(Patient.class, input);
fail();
} catch (DataFormatException e) {
assertThat(e.toString(), containsString("Extension element has no 'url' attribute"));
}
}
@Test
public void testModifierExceptionWithoutUrl() {
//@formatter:off
String input =
"<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?>" +
"<Patient xmlns=\"http://hl7.org/fhir\">" +
"<modifierExtension>" +
"<valueString value=\"FOO\">" +
"</modifierExtension>" +
"<address>" +
"<line value=\"FOO\"/>" +
"</address>" +
"</Patient>";
//@formatter:on
try {
ourCtx.newXmlParser().parseResource(Patient.class, input);
fail();
} catch (DataFormatException e) {
assertThat(e.toString(), containsString("Extension element has no 'url' attribute"));
}
}
@Test
public void testMoreExtensions() throws Exception {
@ -2713,6 +2784,7 @@ public class XmlParserDstu3Test {
}
}
/**
* See #339
*

View File

@ -0,0 +1,90 @@
package ca.uhn.fhir.util;
import static org.junit.Assert.fail;
import javax.xml.parsers.FactoryConfigurationError;
import javax.xml.stream.XMLStreamException;
import org.hl7.fhir.dstu3.model.Patient;
import org.junit.After;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.Test;
import ca.uhn.fhir.context.ConfigurationException;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.model.api.Bundle;
import ca.uhn.fhir.parser.DataFormatException;
public class XmlUtilDstu3Test {
private static FhirContext ourCtx = FhirContext.forDstu3();
private Patient myPatient;
@After
public void after() {
XmlUtil.setThrowExceptionForUnitTest(null);
}
@Before
public void before() {
myPatient = new Patient();
myPatient.setId("1");
}
@Test
public void testParseMalformed() {
try {
ourCtx.newXmlParser().parseResource("AAAAA");
fail();
} catch (DataFormatException e) {
// good
}
}
public void testXmlFactoryThrowsXmlStreamException() {
XmlUtil.setThrowExceptionForUnitTest(new XMLStreamException("FOO"));
try {
ourCtx.newXmlParser().parseResource("AAAAA");
fail();
} catch (DataFormatException e) {
// good
}
try {
ourCtx.newXmlParser().encodeResourceToString(myPatient);
fail();
} catch (ConfigurationException e) {
// good
}
try {
ourCtx.newXmlParser().encodeBundleToString(new Bundle());
fail();
} catch (ConfigurationException e) {
// good
}
}
public void testXmlFactoryThrowsFactoryConfigurationError() {
XmlUtil.setThrowExceptionForUnitTest(new FactoryConfigurationError("FOO"));
try {
ourCtx.newXmlParser().parseResource("AAAAA");
fail();
} catch (DataFormatException e) {
// good
}
try {
ourCtx.newXmlParser().encodeResourceToString(myPatient);
fail();
} catch (ConfigurationException e) {
// good
}
}
@AfterClass
public static void afterClassClearContext() {
TestUtil.clearAllStaticFieldsForUnitTest();
}
}

View File

@ -391,6 +391,10 @@
causing issues on some Android phones which come with an older version
of this library bundled. Thanks to Paolo Perliti for reporting!
</action>
<action type="fix">
Parser is now better able to handle encoding fields which have been
populated with a class that extends the expected class
</action>
</release>
<release version="1.5" date="2016-04-20">
<action type="fix" issue="339">