Fix #207 - Confusing error message parsing invalid contained resources
This commit is contained in:
parent
c2fba2ce21
commit
6941f92090
|
@ -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;
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
||||||
|
|
|
@ -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";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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")
|
||||||
|
|
|
@ -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());
|
||||||
}
|
}
|
||||||
|
|
|
@ -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">
|
||||||
|
|
Loading…
Reference in New Issue