Fix #207 - Confusing error message parsing invalid contained resources

This commit is contained in:
jamesagnew 2015-08-17 20:46:56 -04:00
parent c2fba2ce21
commit 6941f92090
8 changed files with 64 additions and 29 deletions

View File

@ -1123,9 +1123,9 @@ public class JsonParser extends BaseParser implements IParser {
JsonObject nextObject = (JsonObject) theJsonVal; JsonObject nextObject = (JsonObject) theJsonVal;
boolean preResource = false; boolean preResource = false;
if (theState.isPreResource()) { if (theState.isPreResource()) {
String resType = nextObject.getString("resourceType"); String resType = nextObject.getString("resourceType", null);
if (isBlank(resType)) { if (isBlank(resType)) {
throw new DataFormatException("Missing 'resourceType' from resource"); throw new DataFormatException("Missing required element 'resourceType' from JSON resource object, unable to parse");
} }
theState.enteringNewElement(null, resType); theState.enteringNewElement(null, resType);
preResource = true; preResource = true;

View File

@ -328,7 +328,7 @@ public abstract class BaseMethodBinding<T> implements IClientResponseHandler<T>
} }
/** /**
* Subclasses may override this method (but should also call super.{@link #populateActionRequestDetailsForInterceptor(ActionRequestDetails, Object[])) to provide method specifics to the * Subclasses may override this method (but should also call super.{@link #populateActionRequestDetailsForInterceptor(RequestDetails, ActionRequestDetails, Object[])} to provide method specifics to the
* interceptors. * interceptors.
* *
* @param theRequestDetails * @param theRequestDetails

View File

@ -9,6 +9,8 @@ import java.util.Map;
import org.hl7.fhir.instance.model.api.IBaseOperationOutcome; import org.hl7.fhir.instance.model.api.IBaseOperationOutcome;
import ca.uhn.fhir.rest.server.IResourceProvider;
/* /*
* #%L * #%L
* HAPI FHIR - Core Library * HAPI FHIR - Core Library
@ -32,6 +34,18 @@ import org.hl7.fhir.instance.model.api.IBaseOperationOutcome;
/** /**
* Base class for RESTful client and server exceptions. RESTful client methods will only throw exceptions which are subclasses of this exception type, and RESTful server methods should also only call * Base class for RESTful client and server exceptions. RESTful client methods will only throw exceptions which are subclasses of this exception type, and RESTful server methods should also only call
* subclasses of this exception type. * subclasses of this exception type.
* <p>
* HAPI provides a number of subclasses of BaseServerResponseException, and each one corresponds to a specific
* HTTP status code. For example, if a {@link IResourceProvider resource provider} method throws
* {@link ResourceNotFoundException}, this is a signal to the server that an <code>HTTP 404</code> should
* be returned to the client.
* </p>
* <p>
* <b>See:</b> A complete list of available exceptions is in the <a href="./package-summary.html">package summary</a>.
* If an exception doesn't exist for a condition you want to represent, let us know by filing an
* <a href="https://github.com/jamesagnew/hapi-fhir/issues">issue in our tracker</a>. You may also
* use {@link UnclassifiedServerFailureException} to represent any error code you want.
* </p>
*/ */
public abstract class BaseServerResponseException extends RuntimeException { public abstract class BaseServerResponseException extends RuntimeException {

View File

@ -17,6 +17,8 @@ import ca.uhn.fhir.util.ElementUtil;
@ResourceDef(name = "DiagnosticReport") @ResourceDef(name = "DiagnosticReport")
public class MyDiagnosticReportWithBoundCodeExtension extends DiagnosticReport { public class MyDiagnosticReportWithBoundCodeExtension extends DiagnosticReport {
private static final long serialVersionUID = 1L;
public static final String SP_IMAGING_STUDY = "ImagingStudy"; public static final String SP_IMAGING_STUDY = "ImagingStudy";
/** /**

View File

@ -6,4 +6,6 @@ import ca.uhn.fhir.model.dstu.resource.Organization;
@ResourceDef() @ResourceDef()
public class MyOrganization extends Organization { public class MyOrganization extends Organization {
private static final long serialVersionUID = 1L;
} }

View File

@ -15,6 +15,8 @@ import ca.uhn.fhir.model.primitive.StringDt;
@ResourceDef() @ResourceDef()
public class MyPatient extends Patient { public class MyPatient extends Patient {
private static final long serialVersionUID = 1L;
@Child(name = "importantDates", max = Child.MAX_UNLIMITED) @Child(name = "importantDates", max = Child.MAX_UNLIMITED)
@Extension(url = "http://example.com/dontuse#importantDates", definedLocally = false, isModifier = true) @Extension(url = "http://example.com/dontuse#importantDates", definedLocally = false, isModifier = true)
@Description(shortDefinition = "Some dates of note for the patient") @Description(shortDefinition = "Some dates of note for the patient")

View File

@ -3,11 +3,7 @@ package ca.uhn.fhir.parser;
import static org.hamcrest.Matchers.containsString; import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.not; import static org.hamcrest.Matchers.not;
import static org.hamcrest.Matchers.stringContainsInOrder; import static org.hamcrest.Matchers.stringContainsInOrder;
import static org.junit.Assert.assertEquals; import static org.junit.Assert.*;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertThat;
import java.io.IOException; import java.io.IOException;
import java.util.ArrayList; import java.util.ArrayList;
@ -299,7 +295,6 @@ public class JsonParserDstu2Test {
} }
/** /**
* Fixing #89 * Fixing #89
*/ */
@ -319,7 +314,6 @@ public class JsonParserDstu2Test {
//@formatter:on //@formatter:on
} }
/** /**
* #158 * #158
*/ */
@ -328,10 +322,10 @@ public class JsonParserDstu2Test {
TagList tagList = new TagList(); TagList tagList = new TagList();
tagList.addTag(null, null, null); tagList.addTag(null, null, null);
tagList.addTag(null, null, "Label"); tagList.addTag(null, null, "Label");
Patient p = new Patient(); Patient p = new Patient();
ResourceMetadataKeyEnum.TAG_LIST.put(p, tagList); ResourceMetadataKeyEnum.TAG_LIST.put(p, tagList);
String encoded = ourCtx.newJsonParser().encodeResourceToString(p); String encoded = ourCtx.newJsonParser().encodeResourceToString(p);
assertThat(encoded, not(containsString("tag"))); assertThat(encoded, not(containsString("tag")));
} }
@ -344,10 +338,10 @@ public class JsonParserDstu2Test {
TagList tagList = new TagList(); TagList tagList = new TagList();
tagList.addTag("scheme", "code", null); tagList.addTag("scheme", "code", null);
tagList.addTag(null, null, "Label"); tagList.addTag(null, null, "Label");
Patient p = new Patient(); Patient p = new Patient();
ResourceMetadataKeyEnum.TAG_LIST.put(p, tagList); ResourceMetadataKeyEnum.TAG_LIST.put(p, tagList);
String encoded = ourCtx.newJsonParser().encodeResourceToString(p); String encoded = ourCtx.newJsonParser().encodeResourceToString(p);
assertThat(encoded, containsString("tag")); assertThat(encoded, containsString("tag"));
assertThat(encoded, containsString("scheme")); assertThat(encoded, containsString("scheme"));
@ -415,7 +409,7 @@ public class JsonParserDstu2Test {
Patient p = new Patient(); Patient p = new Patient();
p.setId("123"); p.setId("123");
p.addName().addFamily("ABC"); p.addName().addFamily("ABC");
assertThat(ourCtx.newJsonParser().encodeResourceToString(p), stringContainsInOrder("123", "ABC")); assertThat(ourCtx.newJsonParser().encodeResourceToString(p), stringContainsInOrder("123", "ABC"));
assertThat(ourCtx.newJsonParser().setOmitResourceId(true).encodeResourceToString(p), containsString("ABC")); assertThat(ourCtx.newJsonParser().setOmitResourceId(true).encodeResourceToString(p), containsString("ABC"));
assertThat(ourCtx.newJsonParser().setOmitResourceId(true).encodeResourceToString(p), not(containsString("123"))); assertThat(ourCtx.newJsonParser().setOmitResourceId(true).encodeResourceToString(p), not(containsString("123")));
@ -444,7 +438,7 @@ public class JsonParserDstu2Test {
Medication m = (Medication) parsed.getEntries().get(1).getResource(); Medication m = (Medication) parsed.getEntries().get(1).getResource();
assertEquals("http://example.com/base/Medication/example", m.getId().getValue()); assertEquals("http://example.com/base/Medication/example", m.getId().getValue());
assertSame(((ResourceReferenceDt)p.getMedication()).getResource(), m); assertSame(((ResourceReferenceDt) p.getMedication()).getResource(), m);
String reencoded = ourCtx.newJsonParser().setPrettyPrint(true).encodeBundleToString(parsed); String reencoded = ourCtx.newJsonParser().setPrettyPrint(true).encodeBundleToString(parsed);
ourLog.info(reencoded); ourLog.info(reencoded);
@ -474,9 +468,9 @@ public class JsonParserDstu2Test {
ca.uhn.fhir.model.dstu2.resource.Bundle parsed = ourCtx.newXmlParser().parseResource(ca.uhn.fhir.model.dstu2.resource.Bundle.class, content); ca.uhn.fhir.model.dstu2.resource.Bundle parsed = ourCtx.newXmlParser().parseResource(ca.uhn.fhir.model.dstu2.resource.Bundle.class, content);
MedicationPrescription p = (MedicationPrescription) parsed.getEntry().get(0).getResource(); MedicationPrescription p = (MedicationPrescription) parsed.getEntry().get(0).getResource();
assertEquals("#med", ((ResourceReferenceDt)p.getMedication()).getReference().getValue()); assertEquals("#med", ((ResourceReferenceDt) p.getMedication()).getReference().getValue());
Medication m = (Medication) ((ResourceReferenceDt)p.getMedication()).getResource(); Medication m = (Medication) ((ResourceReferenceDt) p.getMedication()).getResource();
assertNotNull(m); assertNotNull(m);
assertEquals("#med", m.getId().getValue()); assertEquals("#med", m.getId().getValue());
assertEquals(1, p.getContained().getContainedResources().size()); assertEquals(1, p.getContained().getContainedResources().size());
@ -514,8 +508,8 @@ public class JsonParserDstu2Test {
Medication m = (Medication) parsed.getEntry().get(1).getResource(); Medication m = (Medication) parsed.getEntry().get(1).getResource();
assertEquals("http://example.com/base/Medication/example", m.getId().getValue()); assertEquals("http://example.com/base/Medication/example", m.getId().getValue());
assertEquals("Medication/example", ((ResourceReferenceDt)p.getMedication()).getReference().getValue()); assertEquals("Medication/example", ((ResourceReferenceDt) p.getMedication()).getReference().getValue());
assertSame(((ResourceReferenceDt)p.getMedication()).getResource(), m); assertSame(((ResourceReferenceDt) p.getMedication()).getResource(), m);
String reencoded = ourCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(parsed); String reencoded = ourCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(parsed);
ourLog.info(reencoded); ourLog.info(reencoded);
@ -554,8 +548,8 @@ public class JsonParserDstu2Test {
Medication m = (Medication) parsed.getEntries().get(1).getResource(); Medication m = (Medication) parsed.getEntries().get(1).getResource();
assertEquals("http://example.com/base/Medication/example", m.getId().getValue()); assertEquals("http://example.com/base/Medication/example", m.getId().getValue());
assertEquals("Medication/example", ((ResourceReferenceDt)p.getMedication()).getReference().getValue()); assertEquals("Medication/example", ((ResourceReferenceDt) p.getMedication()).getReference().getValue());
assertSame(((ResourceReferenceDt)p.getMedication()).getResource(), m); assertSame(((ResourceReferenceDt) p.getMedication()).getResource(), m);
String reencoded = ourCtx.newJsonParser().setPrettyPrint(true).encodeBundleToString(parsed); String reencoded = ourCtx.newJsonParser().setPrettyPrint(true).encodeBundleToString(parsed);
ourLog.info(reencoded); ourLog.info(reencoded);
@ -665,12 +659,12 @@ public class JsonParserDstu2Test {
" ]" + " ]" +
"}"; "}";
//@formatter:on //@formatter:on
ca.uhn.fhir.model.dstu2.resource.Bundle parsed = ourCtx.newJsonParser().parseResource(ca.uhn.fhir.model.dstu2.resource.Bundle.class, input); ca.uhn.fhir.model.dstu2.resource.Bundle parsed = ourCtx.newJsonParser().parseResource(ca.uhn.fhir.model.dstu2.resource.Bundle.class, input);
String encoded = ourCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(parsed); String encoded = ourCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(parsed);
ourLog.info(encoded); ourLog.info(encoded);
assertEquals("urn:uuid:180f219f-97a8-486d-99d9-ed631fe4fc57", parsed.getEntry().get(0).getResource().getId().getValue()); assertEquals("urn:uuid:180f219f-97a8-486d-99d9-ed631fe4fc57", parsed.getEntry().get(0).getResource().getId().getValue());
assertEquals("urn:uuid:", parsed.getEntry().get(0).getResource().getId().getBaseUrl()); assertEquals("urn:uuid:", parsed.getEntry().get(0).getResource().getId().getBaseUrl());
assertEquals("180f219f-97a8-486d-99d9-ed631fe4fc57", parsed.getEntry().get(0).getResource().getId().getIdPart()); assertEquals("180f219f-97a8-486d-99d9-ed631fe4fc57", parsed.getEntry().get(0).getResource().getId().getIdPart());
@ -807,6 +801,22 @@ public class JsonParserDstu2Test {
assertNull(ResourceMetadataKeyEnum.PROFILES.get(patient)); assertNull(ResourceMetadataKeyEnum.PROFILES.get(patient));
} }
/**
* See #207
*/
@Test
public void testParseResourceWithInvalidType() {
String input = "{" + "\"resourceType\":\"Patient\"," + "\"contained\":[" + " {" + " \"rezType\":\"Organization\"" + " }" + " ]" + "}";
IParser jsonParser = ourCtx.newJsonParser().setPrettyPrint(true);
try {
jsonParser.parseResource(input);
fail();
} catch (DataFormatException e) {
assertEquals("Missing required element 'resourceType' from JSON resource object, unable to parse", e.getMessage());
}
}
/** /**
* See #163 * See #163
*/ */
@ -829,10 +839,10 @@ public class JsonParserDstu2Test {
String bundleText = jsonParser.encodeResourceToString(bundle); String bundleText = jsonParser.encodeResourceToString(bundle);
ourLog.info(bundleText); ourLog.info(bundleText);
ca.uhn.fhir.model.dstu2.resource.Bundle reincarnatedBundle = jsonParser.parseResource (ca.uhn.fhir.model.dstu2.resource.Bundle.class, bundleText); ca.uhn.fhir.model.dstu2.resource.Bundle reincarnatedBundle = jsonParser.parseResource(ca.uhn.fhir.model.dstu2.resource.Bundle.class, bundleText);
Patient reincarnatedPatient = (Patient) reincarnatedBundle.getEntry().get(0).getResource(); Patient reincarnatedPatient = (Patient) reincarnatedBundle.getEntry().get(0).getResource();
assertEquals("Patient", patient.getId().getResourceType()); assertEquals("Patient", patient.getId().getResourceType());
assertEquals("Patient", reincarnatedPatient.getId().getResourceType()); assertEquals("Patient", reincarnatedPatient.getId().getResourceType());
} }

View File

@ -88,6 +88,11 @@
of the appropriate error code for the exception being thrown. Thanks to Nagesh Bashyam of the appropriate error code for the exception being thrown. Thanks to Nagesh Bashyam
for reporting! for reporting!
</action> </action>
<action type="fix" issue="207">
Fix issue in JSON parser where invalid contained resources (missing
a resourceType element) fail to parse with a confusing NullPointerException.
Thanks to GitHub user @hugosoares for reporting!
</action>
</release> </release>
<release version="1.1" date="2015-07-13"> <release version="1.1" date="2015-07-13">
<action type="add"> <action type="add">