Fix #344 - make getResourceDefinition(String) and getElementDefnition(String) case insensitive

This commit is contained in:
jamesagnew 2016-04-25 07:19:31 -04:00
parent c48a5224b4
commit 3fce4cb087
6 changed files with 131 additions and 40 deletions

View File

@ -27,10 +27,8 @@ import java.util.Collections;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Map.Entry;
import org.apache.commons.lang3.Validate; import org.apache.commons.lang3.Validate;
import org.apache.commons.lang3.text.WordUtils;
import org.hl7.fhir.instance.model.api.IBase; import org.hl7.fhir.instance.model.api.IBase;
import org.hl7.fhir.instance.model.api.IBaseBundle; import org.hl7.fhir.instance.model.api.IBaseBundle;
import org.hl7.fhir.instance.model.api.IBaseResource; import org.hl7.fhir.instance.model.api.IBaseResource;
@ -185,9 +183,12 @@ public class FhirContext {
/** /**
* Returns the scanned runtime model for the given type. This is an advanced feature which is generally only needed * Returns the scanned runtime model for the given type. This is an advanced feature which is generally only needed
* for extending the core library. * for extending the core library.
* <p>
* Note that this method is case insensitive!
* </p>
*/ */
public BaseRuntimeElementDefinition<?> getElementDefinition(String theElementName) { public BaseRuntimeElementDefinition<?> getElementDefinition(String theElementName) {
return myNameToElementDefinition.get(theElementName); return myNameToElementDefinition.get(theElementName.toLowerCase());
} }
/** For unit tests only */ /** For unit tests only */
@ -275,23 +276,15 @@ public class FhirContext {
/** /**
* Returns the scanned runtime model for the given type. This is an advanced feature which is generally only needed * Returns the scanned runtime model for the given type. This is an advanced feature which is generally only needed
* for extending the core library. * for extending the core library.
* <p>
* Note that this method is case insensitive!
* </p>
*/ */
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public RuntimeResourceDefinition getResourceDefinition(String theResourceName) { public RuntimeResourceDefinition getResourceDefinition(String theResourceName) {
Validate.notBlank(theResourceName, "theResourceName must not be blank"); Validate.notBlank(theResourceName, "theResourceName must not be blank");
String resourceName = theResourceName; String resourceName = theResourceName.toLowerCase();
/*
* TODO: this is a bit of a hack, really we should have a translation table based on a property file or
* something so that we can detect names like diagnosticreport
*/
if (Character.isLowerCase(resourceName.charAt(0))) {
resourceName = WordUtils.capitalize(resourceName);
}
Validate.notBlank(resourceName, "Resource name must not be blank");
RuntimeResourceDefinition retVal = myNameToResourceDefinition.get(resourceName); RuntimeResourceDefinition retVal = myNameToResourceDefinition.get(resourceName);
if (retVal == null) { if (retVal == null) {

View File

@ -319,7 +319,7 @@ class ModelScanner {
resourceDef = new RuntimeCompositeDatatypeDefinition(theDatatypeDefinition, theClass, isStandardType(theClass)); resourceDef = new RuntimeCompositeDatatypeDefinition(theDatatypeDefinition, theClass, isStandardType(theClass));
} }
myClassToElementDefinitions.put(theClass, resourceDef); myClassToElementDefinitions.put(theClass, resourceDef);
myNameToElementDefinitions.put(resourceDef.getName(), resourceDef); myNameToElementDefinitions.put(resourceDef.getName().toLowerCase(), resourceDef);
scanCompositeElementForChildren(theClass, resourceDef); scanCompositeElementForChildren(theClass, resourceDef);
} }
@ -709,7 +709,7 @@ class ModelScanner {
myClassToElementDefinitions.put(theClass, resourceDef); myClassToElementDefinitions.put(theClass, resourceDef);
if (primaryNameProvider) { if (primaryNameProvider) {
if (resourceDef.getStructureVersion() == myVersion) { if (resourceDef.getStructureVersion() == myVersion) {
myNameToResourceDefinitions.put(resourceName, resourceDef); myNameToResourceDefinitions.put(resourceName.toLowerCase(), resourceDef);
} }
} }
scanCompositeElementForChildren(theClass, resourceDef); scanCompositeElementForChildren(theClass, resourceDef);

View File

@ -20,6 +20,7 @@ package ca.uhn.fhir.parser;
* #L% * #L%
*/ */
import static org.apache.commons.lang3.StringUtils.defaultIfBlank; import static org.apache.commons.lang3.StringUtils.defaultIfBlank;
import static org.apache.commons.lang3.StringUtils.defaultString;
import static org.apache.commons.lang3.StringUtils.isNotBlank; import static org.apache.commons.lang3.StringUtils.isNotBlank;
import static org.apache.commons.lang3.StringUtils.isNotEmpty; import static org.apache.commons.lang3.StringUtils.isNotEmpty;
@ -2090,6 +2091,9 @@ class ParserState<T> {
} }
RuntimeResourceDefinition def = (RuntimeResourceDefinition) definition; RuntimeResourceDefinition def = (RuntimeResourceDefinition) definition;
if (!definition.getName().equals(theLocalPart) && definition.getName().equalsIgnoreCase(theLocalPart)) {
throw new DataFormatException("Unknown resource type '" + theLocalPart + "': Resource names are case sensitive, found similar name: '" + definition.getName() + "'");
}
myInstance = def.newInstance(); myInstance = def.newInstance();
String resourceName = def.getName(); String resourceName = def.getName();

View File

@ -4,6 +4,8 @@ import static org.junit.Assert.assertEquals;
import org.hl7.fhir.dstu3.model.Enumerations.AdministrativeGender; import org.hl7.fhir.dstu3.model.Enumerations.AdministrativeGender;
import org.hl7.fhir.dstu3.model.Patient; import org.hl7.fhir.dstu3.model.Patient;
import org.hl7.fhir.dstu3.model.Reference;
import org.hl7.fhir.dstu3.model.StructureDefinition;
import org.junit.AfterClass; import org.junit.AfterClass;
import org.junit.Test; import org.junit.Test;
@ -23,6 +25,27 @@ public class FhirContextDstu3Test {
TestUtil.clearAllStaticFieldsForUnitTest(); TestUtil.clearAllStaticFieldsForUnitTest();
} }
/**
* See #344
*/
@Test
public void testGetElementDefinitionCaseInsensitive() {
assertEquals(Reference.class, ourCtx.getElementDefinition("reference").getImplementingClass());
assertEquals(Reference.class, ourCtx.getElementDefinition("Reference").getImplementingClass());
assertEquals(Reference.class, ourCtx.getElementDefinition("REFerence").getImplementingClass());
}
/**
* See #344
*/
@Test
public void testGetResourceDefinitionCaseInsensitive() {
assertEquals(Patient.class, ourCtx.getResourceDefinition("patient").getImplementingClass());
assertEquals(Patient.class, ourCtx.getResourceDefinition("Patient").getImplementingClass());
assertEquals(Patient.class, ourCtx.getResourceDefinition("PATient").getImplementingClass());
assertEquals(StructureDefinition.class, ourCtx.getResourceDefinition("structuredefinition").getImplementingClass());
}
@Test @Test
public void testCustomTypeDoesntBecomeDefault() { public void testCustomTypeDoesntBecomeDefault() {
FhirContext ctx = FhirContext.forDstu3(); FhirContext ctx = FhirContext.forDstu3();

View File

@ -57,6 +57,8 @@ import org.hl7.fhir.dstu3.model.PrimitiveType;
import org.hl7.fhir.dstu3.model.Quantity; import org.hl7.fhir.dstu3.model.Quantity;
import org.hl7.fhir.dstu3.model.QuestionnaireResponse; import org.hl7.fhir.dstu3.model.QuestionnaireResponse;
import org.hl7.fhir.dstu3.model.Reference; 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.StringType;
import org.hl7.fhir.dstu3.model.Type; import org.hl7.fhir.dstu3.model.Type;
import org.hl7.fhir.dstu3.model.UriType; import org.hl7.fhir.dstu3.model.UriType;
@ -86,6 +88,41 @@ public class JsonParserDstu3Test {
ourCtx.setNarrativeGenerator(null); ourCtx.setNarrativeGenerator(null);
} }
/**
* See #344
*/
@Test
public void testParserIsCaseSensitive() {
Observation obs = new Observation();
SampledData data = new SampledData();
data.setData("1 2 3");
data.setOrigin((SimpleQuantity) new SimpleQuantity().setValue(0L));
data.setPeriod(1000L);
obs.setValue(data);
IParser p = ourCtx.newJsonParser().setPrettyPrint(true).setParserErrorHandler(new StrictErrorHandler());
String encoded = p.encodeResourceToString(obs);
ourLog.info(encoded);
p.parseResource(encoded);
try {
p.parseResource(encoded.replace("Observation", "observation"));
fail();
} catch (DataFormatException e) {
assertEquals("Unknown resource type 'observation': Resource names are case sensitive, found similar name: 'Observation'", e.getMessage());
}
try {
p.parseResource(encoded.replace("valueSampledData", "valueSampleddata"));
fail();
} catch (DataFormatException e) {
assertEquals("Unknown element 'valueSampleddata' found during parse", e.getMessage());
}
}
@Test @Test
public void testEncodeAndParseExtensions() throws Exception { public void testEncodeAndParseExtensions() throws Exception {

View File

@ -82,6 +82,7 @@ import org.hl7.fhir.dstu3.model.PrimitiveType;
import org.hl7.fhir.dstu3.model.Quantity; import org.hl7.fhir.dstu3.model.Quantity;
import org.hl7.fhir.dstu3.model.Reference; import org.hl7.fhir.dstu3.model.Reference;
import org.hl7.fhir.dstu3.model.Resource; import org.hl7.fhir.dstu3.model.Resource;
import org.hl7.fhir.dstu3.model.SampledData;
import org.hl7.fhir.dstu3.model.SimpleQuantity; import org.hl7.fhir.dstu3.model.SimpleQuantity;
import org.hl7.fhir.dstu3.model.StringType; import org.hl7.fhir.dstu3.model.StringType;
import org.hl7.fhir.dstu3.model.UriType; import org.hl7.fhir.dstu3.model.UriType;
@ -114,27 +115,10 @@ public class XmlParserDstu3Test {
ourCtx.setNarrativeGenerator(null); ourCtx.setNarrativeGenerator(null);
} }
/**
* See #347
*/
@Test
public void testEncodeAndParseMedicationOrder() {
MedicationOrder mo = new MedicationOrder();
mo.getDateWrittenElement().setValueAsString("2015-10-05");
String encoded = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(mo);
ourLog.info(encoded);
mo = ourCtx.newXmlParser().parseResource(MedicationOrder.class, encoded);
assertEquals("2015-10-05", mo.getDateWrittenElement().getValueAsString());
}
@Test @Test
public void testBundleWithBinary() { public void testBundleWithBinary() {
//@formatter:off //@formatter:off
String bundle = "<Bundle xmlns=\"http://hl7.org/fhir\">\n" + String bundle = "<Bundle xmlns=\"http://hl7.org/fhir\">\n" +
" <meta/>\n" +
" <base value=\"http://localhost:52788\"/>\n" + " <base value=\"http://localhost:52788\"/>\n" +
" <total value=\"1\"/>\n" + " <total value=\"1\"/>\n" +
" <link>\n" + " <link>\n" +
@ -184,6 +168,8 @@ public class XmlParserDstu3Test {
assertEquals("ORG", o.getName()); assertEquals("ORG", o.getName());
} }
@Test @Test
public void testDuration() { public void testDuration() {
Encounter enc = new Encounter(); Encounter enc = new Encounter();
@ -463,6 +449,21 @@ public class XmlParserDstu3Test {
assertEquals("MR", patient.getIdentifier().get(0).getType().getCoding().get(0).getCode()); assertEquals("MR", patient.getIdentifier().get(0).getType().getCoding().get(0).getCode());
} }
/**
* See #347
*/
@Test
public void testEncodeAndParseMedicationOrder() {
MedicationOrder mo = new MedicationOrder();
mo.getDateWrittenElement().setValueAsString("2015-10-05");
String encoded = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(mo);
ourLog.info(encoded);
mo = ourCtx.newXmlParser().parseResource(MedicationOrder.class, encoded);
assertEquals("2015-10-05", mo.getDateWrittenElement().getValueAsString());
}
@Test @Test
public void testEncodeAndParseMetaProfileAndTags() { public void testEncodeAndParseMetaProfileAndTags() {
Patient p = new Patient(); Patient p = new Patient();
@ -1213,8 +1214,6 @@ public class XmlParserDstu3Test {
assertEquals("<Patient xmlns=\"http://hl7.org/fhir\"><extension url=\"http://hello.world\"><valueString value=\"Hello World\"/></extension></Patient>", xml); assertEquals("<Patient xmlns=\"http://hl7.org/fhir\"><extension url=\"http://hello.world\"><valueString value=\"Hello World\"/></extension></Patient>", xml);
} }
@Test @Test
public void testEncodeReferenceUsingUnqualifiedResourceWorksCorrectly() { public void testEncodeReferenceUsingUnqualifiedResourceWorksCorrectly() {
@ -1252,6 +1251,8 @@ public class XmlParserDstu3Test {
assertThat(str, containsString("<reference value=\"Observation/phitcc_obs_bp_dia\"/>")); assertThat(str, containsString("<reference value=\"Observation/phitcc_obs_bp_dia\"/>"));
} }
@Test @Test
public void testEncodeSummary() { public void testEncodeSummary() {
Patient patient = new Patient(); Patient patient = new Patient();
@ -2559,6 +2560,39 @@ public class XmlParserDstu3Test {
assertEquals("Patient", reincarnatedPatient.getIdElement().getResourceType()); assertEquals("Patient", reincarnatedPatient.getIdElement().getResourceType());
} }
/**
* See #344
*/
@Test
public void testParserIsCaseSensitive() {
Observation obs = new Observation();
SampledData data = new SampledData();
data.setData("1 2 3");
data.setOrigin((SimpleQuantity) new SimpleQuantity().setValue(0L));
data.setPeriod(1000L);
obs.setValue(data);
IParser p = ourCtx.newXmlParser().setPrettyPrint(true).setParserErrorHandler(new StrictErrorHandler());
String encoded = p.encodeResourceToString(obs);
ourLog.info(encoded);
p.parseResource(encoded);
try {
p.parseResource(encoded.replace("Observation", "observation"));
fail();
} catch (DataFormatException e) {
assertEquals("DataFormatException at [[row,col {unknown-source}]: [1,1]]: Unknown resource type 'observation': Resource names are case sensitive, found similar name: 'Observation'", e.getMessage());
}
try {
p.parseResource(encoded.replace("valueSampledData", "valueSampleddata"));
fail();
} catch (DataFormatException e) {
assertEquals("DataFormatException at [[row,col {unknown-source}]: [2,4]]: Unknown element 'valueSampleddata' found during parse", e.getMessage());
}
}
/** /**
* See #339 * See #339
* *