diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/context/FhirContext.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/context/FhirContext.java
index 740a49f4005..c542cc2967e 100644
--- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/context/FhirContext.java
+++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/context/FhirContext.java
@@ -27,10 +27,8 @@ import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
-import java.util.Map.Entry;
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.IBaseBundle;
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
* for extending the core library.
+ *
+ * Note that this method is case insensitive!
+ *
*/
public BaseRuntimeElementDefinition> getElementDefinition(String theElementName) {
- return myNameToElementDefinition.get(theElementName);
+ return myNameToElementDefinition.get(theElementName.toLowerCase());
}
/** 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
* for extending the core library.
+ *
+ * Note that this method is case insensitive!
+ *
*/
@SuppressWarnings("unchecked")
public RuntimeResourceDefinition getResourceDefinition(String theResourceName) {
Validate.notBlank(theResourceName, "theResourceName must not be blank");
- String resourceName = theResourceName;
-
- /*
- * 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");
-
+ String resourceName = theResourceName.toLowerCase();
RuntimeResourceDefinition retVal = myNameToResourceDefinition.get(resourceName);
if (retVal == null) {
diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/context/ModelScanner.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/context/ModelScanner.java
index 461abc41be1..51c904bd2b1 100644
--- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/context/ModelScanner.java
+++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/context/ModelScanner.java
@@ -319,7 +319,7 @@ class ModelScanner {
resourceDef = new RuntimeCompositeDatatypeDefinition(theDatatypeDefinition, theClass, isStandardType(theClass));
}
myClassToElementDefinitions.put(theClass, resourceDef);
- myNameToElementDefinitions.put(resourceDef.getName(), resourceDef);
+ myNameToElementDefinitions.put(resourceDef.getName().toLowerCase(), resourceDef);
scanCompositeElementForChildren(theClass, resourceDef);
}
@@ -709,7 +709,7 @@ class ModelScanner {
myClassToElementDefinitions.put(theClass, resourceDef);
if (primaryNameProvider) {
if (resourceDef.getStructureVersion() == myVersion) {
- myNameToResourceDefinitions.put(resourceName, resourceDef);
+ myNameToResourceDefinitions.put(resourceName.toLowerCase(), resourceDef);
}
}
scanCompositeElementForChildren(theClass, resourceDef);
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 51f71c70c13..efe5504c589 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
@@ -20,6 +20,7 @@ package ca.uhn.fhir.parser;
* #L%
*/
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.isNotEmpty;
@@ -2090,6 +2091,9 @@ class ParserState {
}
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();
String resourceName = def.getName();
diff --git a/hapi-fhir-structures-dstu3/src/test/java/ca/uhn/fhir/context/FhirContextDstu3Test.java b/hapi-fhir-structures-dstu3/src/test/java/ca/uhn/fhir/context/FhirContextDstu3Test.java
index 1f19c8623da..2f6f7c76434 100644
--- a/hapi-fhir-structures-dstu3/src/test/java/ca/uhn/fhir/context/FhirContextDstu3Test.java
+++ b/hapi-fhir-structures-dstu3/src/test/java/ca/uhn/fhir/context/FhirContextDstu3Test.java
@@ -4,6 +4,8 @@ import static org.junit.Assert.assertEquals;
import org.hl7.fhir.dstu3.model.Enumerations.AdministrativeGender;
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.Test;
@@ -22,7 +24,28 @@ public class FhirContextDstu3Test {
public static void afterClassClearContext() {
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
public void testCustomTypeDoesntBecomeDefault() {
FhirContext ctx = FhirContext.forDstu3();
diff --git a/hapi-fhir-structures-dstu3/src/test/java/ca/uhn/fhir/parser/JsonParserDstu3Test.java b/hapi-fhir-structures-dstu3/src/test/java/ca/uhn/fhir/parser/JsonParserDstu3Test.java
index a26bf977348..b02ee0fb0de 100644
--- a/hapi-fhir-structures-dstu3/src/test/java/ca/uhn/fhir/parser/JsonParserDstu3Test.java
+++ b/hapi-fhir-structures-dstu3/src/test/java/ca/uhn/fhir/parser/JsonParserDstu3Test.java
@@ -57,6 +57,8 @@ import org.hl7.fhir.dstu3.model.PrimitiveType;
import org.hl7.fhir.dstu3.model.Quantity;
import org.hl7.fhir.dstu3.model.QuestionnaireResponse;
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.Type;
import org.hl7.fhir.dstu3.model.UriType;
@@ -86,6 +88,41 @@ public class JsonParserDstu3Test {
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
public void testEncodeAndParseExtensions() throws Exception {
diff --git a/hapi-fhir-structures-dstu3/src/test/java/ca/uhn/fhir/parser/XmlParserDstu3Test.java b/hapi-fhir-structures-dstu3/src/test/java/ca/uhn/fhir/parser/XmlParserDstu3Test.java
index 9ab68cfbbd0..03544844afa 100644
--- a/hapi-fhir-structures-dstu3/src/test/java/ca/uhn/fhir/parser/XmlParserDstu3Test.java
+++ b/hapi-fhir-structures-dstu3/src/test/java/ca/uhn/fhir/parser/XmlParserDstu3Test.java
@@ -82,6 +82,7 @@ import org.hl7.fhir.dstu3.model.PrimitiveType;
import org.hl7.fhir.dstu3.model.Quantity;
import org.hl7.fhir.dstu3.model.Reference;
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.StringType;
import org.hl7.fhir.dstu3.model.UriType;
@@ -114,27 +115,10 @@ public class XmlParserDstu3Test {
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
public void testBundleWithBinary() {
//@formatter:off
String bundle = "\n" +
- " \n" +
" \n" +
" \n" +
" \n" +
@@ -184,6 +168,8 @@ public class XmlParserDstu3Test {
assertEquals("ORG", o.getName());
}
+
+
@Test
public void testDuration() {
Encounter enc = new Encounter();
@@ -197,7 +183,7 @@ public class XmlParserDstu3Test {
assertThat(str, not(containsString("meta")));
assertThat(str, containsString(""));
}
-
+
@Test
public void testEncodeAndParseBundleWithResourceRefs() {
@@ -234,7 +220,7 @@ public class XmlParserDstu3Test {
assertEquals("Organization/orgid", pt.getManagingOrganization().getReferenceElement().getValue());
assertSame(org, pt.getManagingOrganization().getResource());
}
-
+
@Test
public void testEncodeAndParseContained() {
IParser xmlParser = ourCtx.newXmlParser().setPrettyPrint(true);
@@ -463,6 +449,21 @@ public class XmlParserDstu3Test {
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
public void testEncodeAndParseMetaProfileAndTags() {
Patient p = new Patient();
@@ -1213,8 +1214,6 @@ public class XmlParserDstu3Test {
assertEquals("", xml);
}
-
-
@Test
public void testEncodeReferenceUsingUnqualifiedResourceWorksCorrectly() {
@@ -1252,6 +1251,8 @@ public class XmlParserDstu3Test {
assertThat(str, containsString(""));
}
+
+
@Test
public void testEncodeSummary() {
Patient patient = new Patient();
@@ -1290,7 +1291,7 @@ public class XmlParserDstu3Test {
assertThat(encoded, containsString("family"));
assertThat(encoded, not(containsString("maritalStatus")));
}
-
+
@Test
public void testEncodeUndeclaredExtensionWithEnumerationContent() {
IParser parser = ourCtx.newXmlParser();
@@ -1311,7 +1312,7 @@ public class XmlParserDstu3Test {
assertEquals("home", ref.getValue().toCode());
}
-
+
@Test
public void testEncodeWithContained() {
List contained = new ArrayList();
@@ -2559,6 +2560,39 @@ public class XmlParserDstu3Test {
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
*