Improve error message when JSON parser finds an object where an array is expected

This commit is contained in:
jamesagnew 2015-09-24 07:20:06 -04:00
parent cdc1519a55
commit 7e6844be56
4 changed files with 110 additions and 18 deletions

View File

@ -1014,7 +1014,7 @@ public class JsonParser extends BaseParser implements IParser {
if ("resourceType".equals(nextName)) { if ("resourceType".equals(nextName)) {
continue; continue;
} else if ("entry".equals(nextName)) { } else if ("entry".equals(nextName)) {
JsonArray entries = theObject.getJsonArray(nextName); JsonArray entries = grabJsonArray(theObject, nextName, "entry");
for (JsonValue jsonValue : entries) { for (JsonValue jsonValue : entries) {
theState.enteringNewElement(null, "entry"); theState.enteringNewElement(null, "entry");
parseBundleChildren((JsonObject) jsonValue, theState); parseBundleChildren((JsonObject) jsonValue, theState);
@ -1023,7 +1023,7 @@ public class JsonParser extends BaseParser implements IParser {
continue; continue;
} else if (myContext.getVersion().getVersion() == FhirVersionEnum.DSTU1) { } else if (myContext.getVersion().getVersion() == FhirVersionEnum.DSTU1) {
if ("link".equals(nextName)) { if ("link".equals(nextName)) {
JsonArray entries = theObject.getJsonArray(nextName); JsonArray entries = grabJsonArray(theObject, nextName, "link");
for (JsonValue jsonValue : entries) { for (JsonValue jsonValue : entries) {
theState.enteringNewElement(null, "link"); theState.enteringNewElement(null, "link");
JsonObject linkObj = (JsonObject) jsonValue; JsonObject linkObj = (JsonObject) jsonValue;
@ -1042,7 +1042,7 @@ public class JsonParser extends BaseParser implements IParser {
} }
} else { } else {
if ("link".equals(nextName)) { if ("link".equals(nextName)) {
JsonArray entries = theObject.getJsonArray(nextName); JsonArray entries = grabJsonArray(theObject, nextName, "link");
for (JsonValue jsonValue : entries) { for (JsonValue jsonValue : entries) {
theState.enteringNewElement(null, "link"); theState.enteringNewElement(null, "link");
JsonObject linkObj = (JsonObject) jsonValue; JsonObject linkObj = (JsonObject) jsonValue;
@ -1106,11 +1106,11 @@ public class JsonParser extends BaseParser implements IParser {
} }
continue; continue;
} else if ("extension".equals(nextName)) { } else if ("extension".equals(nextName)) {
JsonArray array = theObject.getJsonArray(nextName); JsonArray array = grabJsonArray(theObject, nextName, "extension");
parseExtension(theState, array, false); parseExtension(theState, array, false);
continue; continue;
} else if ("modifierExtension".equals(nextName)) { } else if ("modifierExtension".equals(nextName)) {
JsonArray array = theObject.getJsonArray(nextName); JsonArray array = grabJsonArray(theObject, nextName, "modifierExtension");
parseExtension(theState, array, true); parseExtension(theState, array, true);
continue; continue;
} else if (nextName.charAt(0) == '_') { } else if (nextName.charAt(0) == '_') {
@ -1135,6 +1135,17 @@ public class JsonParser extends BaseParser implements IParser {
} }
} }
private JsonArray grabJsonArray(JsonObject theObject, String nextName, String thePosition) {
JsonValue object = theObject.get(nextName);
if (object == null) {
return null;
}
if (object.getValueType() != ValueType.ARRAY) {
throw new DataFormatException("Syntax error parsing JSON FHIR structure: Expected ARRAY at element '" + thePosition + "', found '" + object.getValueType().name() + "'");
}
return (JsonArray) object;
}
private void parseChildren(ParserState<?> theState, String theName, JsonValue theJsonVal, JsonValue theAlternateVal, String theAlternateName) { private void parseChildren(ParserState<?> theState, String theName, JsonValue theJsonVal, JsonValue theAlternateVal, String theAlternateName) {
switch (theJsonVal.getValueType()) { switch (theJsonVal.getValueType()) {
case ARRAY: { case ARRAY: {

View File

@ -28,6 +28,7 @@ import ca.uhn.fhir.model.dstu2.composite.HumanNameDt;
import ca.uhn.fhir.model.dstu2.composite.ResourceReferenceDt; import ca.uhn.fhir.model.dstu2.composite.ResourceReferenceDt;
import ca.uhn.fhir.model.dstu2.resource.Binary; import ca.uhn.fhir.model.dstu2.resource.Binary;
import ca.uhn.fhir.model.dstu2.resource.Bundle.Entry; import ca.uhn.fhir.model.dstu2.resource.Bundle.Entry;
import ca.uhn.fhir.model.dstu2.resource.Conformance;
import ca.uhn.fhir.model.dstu2.resource.DiagnosticReport; import ca.uhn.fhir.model.dstu2.resource.DiagnosticReport;
import ca.uhn.fhir.model.dstu2.resource.Medication; import ca.uhn.fhir.model.dstu2.resource.Medication;
import ca.uhn.fhir.model.dstu2.resource.MedicationOrder; import ca.uhn.fhir.model.dstu2.resource.MedicationOrder;
@ -474,17 +475,6 @@ public class JsonParserDstu2Test {
assertThat(ourCtx.newJsonParser().setOmitResourceId(true).encodeResourceToString(p), not(containsString("123"))); assertThat(ourCtx.newJsonParser().setOmitResourceId(true).encodeResourceToString(p), not(containsString("123")));
} }
@Test
public void testParseAndEncodeBundleResourceWithComments() throws Exception {
String content = IOUtils.toString(JsonParserDstu2Test.class.getResourceAsStream("/bundle-transaction2.json"));
ourCtx.newJsonParser().parseBundle(content);
ca.uhn.fhir.model.dstu2.resource.Bundle parsed = ourCtx.newJsonParser().parseResource(ca.uhn.fhir.model.dstu2.resource.Bundle.class, content);
// TODO: preserve comments
}
@Test @Test
public void testParseAndEncodeBundle() throws Exception { public void testParseAndEncodeBundle() throws Exception {
String content = IOUtils.toString(JsonParserDstu2Test.class.getResourceAsStream("/bundle-example.json")); String content = IOUtils.toString(JsonParserDstu2Test.class.getResourceAsStream("/bundle-example.json"));
@ -527,7 +517,7 @@ public class JsonParserDstu2Test {
assertEquals(exp, act); assertEquals(exp, act);
} }
/** /**
* Test for #146 * Test for #146
*/ */
@ -641,6 +631,17 @@ public class JsonParserDstu2Test {
} }
@Test
public void testParseAndEncodeBundleResourceWithComments() throws Exception {
String content = IOUtils.toString(JsonParserDstu2Test.class.getResourceAsStream("/bundle-transaction2.json"));
ourCtx.newJsonParser().parseBundle(content);
ca.uhn.fhir.model.dstu2.resource.Bundle parsed = ourCtx.newJsonParser().parseResource(ca.uhn.fhir.model.dstu2.resource.Bundle.class, content);
// TODO: preserve comments
}
@Test @Test
public void testParseAndEncodeBundleWithDeletedEntry() { public void testParseAndEncodeBundleWithDeletedEntry() {
@ -856,7 +857,7 @@ public class JsonParserDstu2Test {
assertEquals(exp, act); assertEquals(exp, act);
} }
@Test @Test
public void testParsePatientInBundle() { public void testParsePatientInBundle() {
@ -917,6 +918,17 @@ public class JsonParserDstu2Test {
} }
} }
@Test
public void testParseWithWrongTypeObjectShouldBeArray() throws Exception {
String input = IOUtils.toString(getClass().getResourceAsStream("/invalid_metadata.json"));
try {
ourCtx.newJsonParser().parseResource(Conformance.class, input);
fail();
} catch (DataFormatException e) {
assertEquals("Syntax error parsing JSON FHIR structure: Expected ARRAY at element 'modifierExtension', found 'OBJECT'", e.getMessage());
}
}
/** /**
* See #144 and #146 * See #144 and #146
*/ */

View File

@ -0,0 +1,65 @@
{
"resourceType": "Conformance",
"meta": {
"versionId": "0.0.1"
},
"status": "draft",
"experimental": true,
"date": "2015-09-23T12:00:00Z",
"fhirVersion": "DSTU 2 0.5.0",
"acceptUnknown": false,
"format": [
"json"
],
"rest": [
{
"mode": "server",
"documentation": "Information about the system's restful capabilities that apply across all applications, such as security",
"security": {
"cors": false,
"service": [
{
"coding": [
{
"system": "http://hl7.org/fhir/restful-security-service",
"code": "OAuth"
}
]
}
],
"description": "General description of how security works",
"certificate": [
{
"type": "json"
}
],
"modifierExtension": {
"url": "http://fhir-registry.smarthealthit.org/StructureDefinition/oauth-uris"
},
"extension": {
"url": "http://fhir-registry.smarthealthit.org/StructureDefinition/oauth-uris"
}
},
"resource": [
{
"type": "Patient",
"profile": {
"reference": "http://hl7.org/fhir/StructureDefinition/patient-daf-dafpatient"
},
"interaction": [
{
"code": "read"
},
{
"code": "update"
},
{
"code": "search-type"
}
],
"versioning": "no-version"
}
]
}
]
}

View File

@ -37,6 +37,10 @@
Constructor for DateRanfeParam which dates in two DateParam instances was ignoring Constructor for DateRanfeParam which dates in two DateParam instances was ignoring
comparators on the DateParam. comparators on the DateParam.
</action> </action>
<action type="fix">
In JSON parsing, finding an object where an array was expected led to an unhelpful
error message. Thanks to Avinash Shanbhag for reporting!
</action>
</release> </release>
<release version="1.2" date="2015-09-18"> <release version="1.2" date="2015-09-18">
<action type="add"> <action type="add">