Fix #414: Parser should not choke with a NullPointerException if it
encounters an extension without a URL
This commit is contained in:
parent
22c2d301dc
commit
26cd316343
|
@ -130,6 +130,7 @@ public class ExtensionDt extends BaseIdentifiableElement implements ICompositeDa
|
|||
myModifier = theModifier;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ExtensionDt setUrl(String theUrl) {
|
||||
myUrl = theUrl != null ? new StringDt(theUrl) : myUrl;
|
||||
return this;
|
||||
|
@ -140,6 +141,7 @@ public class ExtensionDt extends BaseIdentifiableElement implements ICompositeDa
|
|||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ExtensionDt setValue(IBaseDatatype theValue) {
|
||||
myValue = theValue;
|
||||
return this;
|
||||
|
|
|
@ -50,4 +50,9 @@ public class ErrorHandlerAdapter implements IParserErrorHandler {
|
|||
// NOP
|
||||
}
|
||||
|
||||
@Override
|
||||
public void missingRequiredElement(IParseLocation theLocation, String theElementName) {
|
||||
// NOP
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
package ca.uhn.fhir.parser;
|
||||
|
||||
import ca.uhn.fhir.parser.IParserErrorHandler.IParseLocation;
|
||||
|
||||
/*
|
||||
* #%L
|
||||
* HAPI FHIR - Core Library
|
||||
|
@ -35,13 +37,22 @@ public interface IParserErrorHandler {
|
|||
*/
|
||||
void containedResourceWithNoId(IParseLocation theLocation);
|
||||
|
||||
/**
|
||||
* Resource was missing a required element
|
||||
*
|
||||
* @param theLocation
|
||||
* The location in the document. Note that this may be <code>null</code> as the ParseLocation feature is experimental. Use with caution, as the API may change.
|
||||
* @param theReference The actual invalid reference (e.g. "#3")
|
||||
* @since 2.1
|
||||
*/
|
||||
void missingRequiredElement(IParseLocation theLocation, String theElementName);
|
||||
|
||||
/**
|
||||
* Invoked when an element repetition (e.g. a second repetition of something) is found for a field
|
||||
* which is non-repeating.
|
||||
*
|
||||
* @param theLocation
|
||||
* The location in the document. WILL ALWAYS BE NULL currently, as this is not yet implemented, but this parameter is included so that locations can be added in the future without
|
||||
* changing the API.
|
||||
* The location in the document. Note that this may be <code>null</code> as the ParseLocation feature is experimental. Use with caution, as the API may change.
|
||||
* @param theElementName
|
||||
* The name of the element that was found.
|
||||
* @since 1.2
|
||||
|
@ -52,8 +63,7 @@ public interface IParserErrorHandler {
|
|||
* Invoked when an unknown element is found in the document.
|
||||
*
|
||||
* @param theLocation
|
||||
* The location in the document. WILL ALWAYS BE NULL currently, as this is not yet implemented, but this parameter is included so that locations can be added in the future without
|
||||
* changing the API.
|
||||
* The location in the document. Note that this may be <code>null</code> as the ParseLocation feature is experimental. Use with caution, as the API may change.
|
||||
* @param theAttributeName
|
||||
* The name of the attribute that was found.
|
||||
*/
|
||||
|
@ -63,8 +73,7 @@ public interface IParserErrorHandler {
|
|||
* Invoked when an unknown element is found in the document.
|
||||
*
|
||||
* @param theLocation
|
||||
* The location in the document. WILL ALWAYS BE NULL currently, as this is not yet implemented, but this parameter is included so that locations can be added in the future without
|
||||
* changing the API.
|
||||
* The location in the document. Note that this may be <code>null</code> as the ParseLocation feature is experimental. Use with caution, as the API may change.
|
||||
* @param theElementName
|
||||
* The name of the element that was found.
|
||||
*/
|
||||
|
@ -75,8 +84,7 @@ public interface IParserErrorHandler {
|
|||
* it is a local reference to an unknown contained resource)
|
||||
*
|
||||
* @param theLocation
|
||||
* The location in the document. WILL ALWAYS BE NULL currently, as this is not yet implemented, but this parameter is included so that locations can be added in the future without
|
||||
* changing the API.
|
||||
* The location in the document. Note that this may be <code>null</code> as the ParseLocation feature is experimental. Use with caution, as the API may change.
|
||||
* @param theReference The actual invalid reference (e.g. "#3")
|
||||
* @since 2.0
|
||||
*/
|
||||
|
@ -88,7 +96,13 @@ public interface IParserErrorHandler {
|
|||
* locations can be added to the API in a future release without changing the API.
|
||||
*/
|
||||
public interface IParseLocation {
|
||||
// nothing for now
|
||||
|
||||
/**
|
||||
* Returns the name of the parent element (the element containing the element currently being parsed)
|
||||
* @since 2.1
|
||||
*/
|
||||
String getParentElementName();
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1299,7 +1299,20 @@ public class JsonParser extends BaseParser implements IParser {
|
|||
private void parseExtension(ParserState<?> theState, JsonArray theValues, boolean theIsModifier) {
|
||||
for (int i = 0; i < theValues.size(); i++) {
|
||||
JsonObject nextExtObj = (JsonObject) theValues.get(i);
|
||||
String url = nextExtObj.get("url").getAsString();
|
||||
JsonElement jsonElement = nextExtObj.get("url");
|
||||
String url;
|
||||
if (!(jsonElement instanceof JsonPrimitive)) {
|
||||
String parentElementName;
|
||||
if (theIsModifier) {
|
||||
parentElementName = "modifierExtension";
|
||||
} else {
|
||||
parentElementName = "extension";
|
||||
}
|
||||
getErrorHandler().missingRequiredElement(new ParseLocation(parentElementName), "url");
|
||||
url = null;
|
||||
} else {
|
||||
url = jsonElement.getAsString();
|
||||
}
|
||||
theState.enteringNewElementExtension(null, url, theIsModifier);
|
||||
for (Iterator<Entry<String, JsonElement>> iter = nextExtObj.entrySet().iterator(); iter.hasNext();) {
|
||||
String next = iter.next().getKey();
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package ca.uhn.fhir.parser;
|
||||
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.parser.IParserErrorHandler.IParseLocation;
|
||||
|
||||
/*
|
||||
* #%L
|
||||
|
@ -85,4 +86,11 @@ public class LenientErrorHandler implements IParserErrorHandler {
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void missingRequiredElement(IParseLocation theLocation, String theElementName) {
|
||||
if (myLogErrors) {
|
||||
ourLog.warn("Resource is missing required element: {}", theElementName);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,22 @@
|
|||
package ca.uhn.fhir.parser;
|
||||
|
||||
import ca.uhn.fhir.parser.IParserErrorHandler.IParseLocation;
|
||||
|
||||
class ParseLocation implements IParseLocation {
|
||||
|
||||
private String myParentElementName;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
public ParseLocation(String theParentElementName) {
|
||||
super();
|
||||
myParentElementName = theParentElementName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getParentElementName() {
|
||||
return myParentElementName;
|
||||
}
|
||||
|
||||
}
|
|
@ -830,7 +830,8 @@ class ParserState<T> {
|
|||
@SuppressWarnings("unused")
|
||||
public void enteringNewElementExtension(StartElement theElement, String theUrlAttr, boolean theIsModifier) {
|
||||
if (myPreResourceState != null && getCurrentElement() instanceof ISupportsUndeclaredExtensions) {
|
||||
ExtensionDt newExtension = new ExtensionDt(theIsModifier, theUrlAttr);
|
||||
ExtensionDt newExtension = new ExtensionDt(theIsModifier);
|
||||
newExtension.setUrl(theUrlAttr);
|
||||
ISupportsUndeclaredExtensions elem = (ISupportsUndeclaredExtensions) getCurrentElement();
|
||||
elem.addUndeclaredExtension(newExtension);
|
||||
ExtensionState newState = new ExtensionState(myPreResourceState, newExtension);
|
||||
|
|
|
@ -56,5 +56,19 @@ public class StrictErrorHandler implements IParserErrorHandler {
|
|||
throw new DataFormatException("Resource has invalid reference: " + theReference);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void missingRequiredElement(IParseLocation theLocation, String theElementName) {
|
||||
StringBuilder b = new StringBuilder();
|
||||
b.append("Resource is missing required element '");
|
||||
b.append(theElementName);
|
||||
b.append("'");
|
||||
if (theLocation != null) {
|
||||
b.append(" in parent element '");
|
||||
b.append(theLocation.getParentElementName());
|
||||
b.append("'");
|
||||
}
|
||||
throw new DataFormatException(b.toString());
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -205,16 +205,24 @@ public class XmlParser extends BaseParser implements IParser {
|
|||
|
||||
if ("extension".equals(elem.getName().getLocalPart())) {
|
||||
Attribute urlAttr = elem.getAttributeByName(new QName("url"));
|
||||
String url;
|
||||
if (urlAttr == null || isBlank(urlAttr.getValue())) {
|
||||
throw new DataFormatException("Extension element has no 'url' attribute");
|
||||
getErrorHandler().missingRequiredElement(new ParseLocation("extension"), "url");
|
||||
url = null;
|
||||
} else {
|
||||
url = urlAttr.getValue();
|
||||
}
|
||||
parserState.enteringNewElementExtension(elem, urlAttr.getValue(), false);
|
||||
parserState.enteringNewElementExtension(elem, url, false);
|
||||
} else if ("modifierExtension".equals(elem.getName().getLocalPart())) {
|
||||
Attribute urlAttr = elem.getAttributeByName(new QName("url"));
|
||||
String url;
|
||||
if (urlAttr == null || isBlank(urlAttr.getValue())) {
|
||||
throw new DataFormatException("Extension element has no 'url' attribute");
|
||||
getErrorHandler().missingRequiredElement(new ParseLocation("modifierExtension"), "url");
|
||||
url = null;
|
||||
} else {
|
||||
url = urlAttr.getValue();
|
||||
}
|
||||
parserState.enteringNewElementExtension(elem, urlAttr.getValue(), true);
|
||||
parserState.enteringNewElementExtension(elem, url, true);
|
||||
} else {
|
||||
String elementName = elem.getName().getLocalPart();
|
||||
parserState.enteringNewElement(namespaceURI, elementName);
|
||||
|
|
|
@ -23,6 +23,7 @@ import java.util.UUID;
|
|||
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.hamcrest.Matchers;
|
||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
@ -106,8 +107,6 @@ public class JsonParserDstu2Test {
|
|||
assertEquals("ORG", o.getName());
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* See #308
|
||||
*/
|
||||
|
@ -125,6 +124,7 @@ public class JsonParserDstu2Test {
|
|||
obs = p.parseResource(ReportObservation.class, encoded);
|
||||
assertEquals(true, obs.getReadOnly().getValue().booleanValue());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* See #390
|
||||
|
@ -245,7 +245,7 @@ public class JsonParserDstu2Test {
|
|||
p = (Patient) ourCtx.newJsonParser().parseResource("{\"resourceType\":\"Patient\",\"language\":[\"en_CA\"]}");
|
||||
assertEquals("en_CA", p.getLanguage().getValue());
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testEncodeAndParseMetaProfileAndTags() {
|
||||
Patient p = new Patient();
|
||||
|
@ -302,7 +302,6 @@ public class JsonParserDstu2Test {
|
|||
assertEquals(new Tag("scheme2", "term2", "label2"), tagList.get(1));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* See #336
|
||||
*/
|
||||
|
@ -360,7 +359,7 @@ public class JsonParserDstu2Test {
|
|||
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Test
|
||||
public void testEncodeAndParseSecurityLabels() {
|
||||
Patient p = new Patient();
|
||||
|
@ -425,7 +424,7 @@ public class JsonParserDstu2Test {
|
|||
assertEquals("VERSION2", label.getVersion());
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Test
|
||||
public void testEncodeBundleNewBundleNoText() {
|
||||
|
||||
|
@ -446,6 +445,7 @@ public class JsonParserDstu2Test {
|
|||
assertThat(val, not(containsString("text")));
|
||||
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testEncodeBundleOldBundleNoText() {
|
||||
|
@ -484,7 +484,7 @@ public class JsonParserDstu2Test {
|
|||
"}"));
|
||||
//@formatter:on
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testEncodeDoesntIncludeUuidId() {
|
||||
Patient p = new Patient();
|
||||
|
@ -535,7 +535,6 @@ public class JsonParserDstu2Test {
|
|||
assertThat(encoded, not(containsString("Label")));
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testEncodeExtensionInPrimitiveElement() {
|
||||
|
||||
|
@ -565,7 +564,7 @@ public class JsonParserDstu2Test {
|
|||
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Test
|
||||
public void testEncodeExtensionUndeclaredNonModifier() {
|
||||
Observation obs = new Observation();
|
||||
|
@ -603,6 +602,7 @@ public class JsonParserDstu2Test {
|
|||
assertEquals("ext_url_value", ((StringDt)obs.getUndeclaredExtensions().get(0).getValue()).getValue());
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testEncodeExtensionUndeclaredNonModifierWithChildExtension() {
|
||||
Observation obs = new Observation();
|
||||
|
@ -1362,6 +1362,66 @@ public class JsonParserDstu2Test {
|
|||
assertEquals("patient family", p.getNameFirstRep().getFamilyAsSingleString());
|
||||
}
|
||||
|
||||
/**
|
||||
* See #414
|
||||
*/
|
||||
@Test
|
||||
public void testParseJsonExtensionWithoutUrl() {
|
||||
//@formatter:off
|
||||
String input =
|
||||
"{\"resourceType\":\"Patient\"," +
|
||||
"\"extension\":[ {\"valueDateTime\":\"2011-01-02T11:13:15\"} ]" +
|
||||
"}";
|
||||
//@formatter:on
|
||||
|
||||
IParser parser = ourCtx.newJsonParser();
|
||||
parser.setParserErrorHandler(new LenientErrorHandler());
|
||||
Patient parsed = (Patient) parser.parseResource(input);
|
||||
assertEquals(1, parsed.getAllUndeclaredExtensions().size());
|
||||
assertEquals(null, parsed.getAllUndeclaredExtensions().get(0).getUrl());
|
||||
assertEquals("2011-01-02T11:13:15", parsed.getAllUndeclaredExtensions().get(0).getValueAsPrimitive().getValueAsString());
|
||||
|
||||
try {
|
||||
parser = ourCtx.newJsonParser();
|
||||
parser.setParserErrorHandler(new StrictErrorHandler());
|
||||
parser.parseResource(input);
|
||||
fail();
|
||||
} catch (DataFormatException e) {
|
||||
assertEquals("Resource is missing required element 'url' in parent element 'extension'", e.getMessage());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* See #414
|
||||
*/
|
||||
@Test
|
||||
public void testParseJsonModifierExtensionWithoutUrl() {
|
||||
//@formatter:off
|
||||
String input =
|
||||
"{\"resourceType\":\"Patient\"," +
|
||||
"\"modifierExtension\":[ {\"valueDateTime\":\"2011-01-02T11:13:15\"} ]" +
|
||||
"}";
|
||||
//@formatter:on
|
||||
|
||||
IParser parser = ourCtx.newJsonParser();
|
||||
parser.setParserErrorHandler(new LenientErrorHandler());
|
||||
Patient parsed = (Patient) parser.parseResource(input);
|
||||
assertEquals(1, parsed.getAllUndeclaredExtensions().size());
|
||||
assertEquals(null, parsed.getAllUndeclaredExtensions().get(0).getUrl());
|
||||
assertEquals("2011-01-02T11:13:15", parsed.getAllUndeclaredExtensions().get(0).getValueAsPrimitive().getValueAsString());
|
||||
|
||||
try {
|
||||
parser = ourCtx.newJsonParser();
|
||||
parser.setParserErrorHandler(new StrictErrorHandler());
|
||||
parser.parseResource(input);
|
||||
fail();
|
||||
} catch (DataFormatException e) {
|
||||
assertEquals("Resource is missing required element 'url' in parent element 'modifierExtension'", e.getMessage());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testParseMetadata() throws Exception {
|
||||
//@formatter:off
|
||||
|
|
|
@ -68,6 +68,69 @@ public class XmlParserDstu2Test {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* See #414
|
||||
*/
|
||||
@Test
|
||||
public void testParseXmlExtensionWithoutUrl() {
|
||||
//@formatter:off
|
||||
String input = "<Patient xmlns=\"http://hl7.org/fhir\">\n" +
|
||||
" <extension>\n" +
|
||||
" <valueDateTime value=\"2011-01-02T11:13:15\"/>\n" +
|
||||
" </extension>\n" +
|
||||
"</Patient>";
|
||||
//@formatter:on
|
||||
|
||||
IParser parser = ourCtx.newXmlParser();
|
||||
parser.setParserErrorHandler(new LenientErrorHandler());
|
||||
Patient parsed = (Patient) parser.parseResource(input);
|
||||
assertEquals(1, parsed.getAllUndeclaredExtensions().size());
|
||||
assertEquals(null, parsed.getAllUndeclaredExtensions().get(0).getUrl());
|
||||
assertEquals("2011-01-02T11:13:15", parsed.getAllUndeclaredExtensions().get(0).getValueAsPrimitive().getValueAsString());
|
||||
|
||||
try {
|
||||
parser = ourCtx.newXmlParser();
|
||||
parser.setParserErrorHandler(new StrictErrorHandler());
|
||||
parser.parseResource(input);
|
||||
fail();
|
||||
} catch (DataFormatException e) {
|
||||
assertEquals("Resource is missing required element 'url' in parent element 'extension'", e.getCause().getMessage());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* See #414
|
||||
*/
|
||||
@Test
|
||||
public void testParseXmlModifierExtensionWithoutUrl() {
|
||||
//@formatter:off
|
||||
String input = "<Patient xmlns=\"http://hl7.org/fhir\">\n" +
|
||||
" <modifierExtension>\n" +
|
||||
" <valueDateTime value=\"2011-01-02T11:13:15\"/>\n" +
|
||||
" </modifierExtension>\n" +
|
||||
"</Patient>";
|
||||
//@formatter:on
|
||||
|
||||
IParser parser = ourCtx.newXmlParser();
|
||||
parser.setParserErrorHandler(new LenientErrorHandler());
|
||||
Patient parsed = (Patient) parser.parseResource(input);
|
||||
assertEquals(1, parsed.getAllUndeclaredExtensions().size());
|
||||
assertEquals(null, parsed.getAllUndeclaredExtensions().get(0).getUrl());
|
||||
assertEquals("2011-01-02T11:13:15", parsed.getAllUndeclaredExtensions().get(0).getValueAsPrimitive().getValueAsString());
|
||||
|
||||
try {
|
||||
parser = ourCtx.newXmlParser();
|
||||
parser.setParserErrorHandler(new StrictErrorHandler());
|
||||
parser.parseResource(input);
|
||||
fail();
|
||||
} catch (DataFormatException e) {
|
||||
assertEquals("Resource is missing required element 'url' in parent element 'modifierExtension'", e.getCause().getMessage());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* If a contained resource refers to a contained resource that comes after it, it should still be successfully
|
||||
* woven together.
|
||||
|
|
|
@ -3,9 +3,13 @@ package org.hl7.fhir.dstu3.model;
|
|||
import org.hl7.fhir.instance.model.api.IBaseDatatype;
|
||||
import org.hl7.fhir.instance.model.api.IBaseExtension;
|
||||
import org.hl7.fhir.instance.model.api.IBaseHasExtensions;
|
||||
import org.hl7.fhir.instance.model.api.IPrimitiveType;
|
||||
|
||||
public abstract class BaseExtension extends Type implements IBaseExtension<Extension, Type>, IBaseHasExtensions {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
|
||||
@Override
|
||||
public Extension setValue(IBaseDatatype theValue) {
|
||||
setValue((Type)theValue);
|
||||
|
@ -14,4 +18,13 @@ public abstract class BaseExtension extends Type implements IBaseExtension<Exten
|
|||
|
||||
public abstract Extension setValue(Type theValue);
|
||||
|
||||
|
||||
/**
|
||||
* Returns the value of this extension cast as a {@link IPrimitiveType}. This method is just a convenience method for easy chaining.
|
||||
*/
|
||||
public IPrimitiveType<?> getValueAsPrimitive() {
|
||||
return (IPrimitiveType<?>)getValue();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -36,6 +36,7 @@ import org.hl7.fhir.exceptions.FHIRException;
|
|||
import org.hl7.fhir.instance.model.api.IBaseDatatype;
|
||||
import org.hl7.fhir.instance.model.api.IBaseExtension;
|
||||
import org.hl7.fhir.instance.model.api.IBaseHasExtensions;
|
||||
import org.hl7.fhir.utilities.xhtml.XhtmlNode;
|
||||
|
||||
import ca.uhn.fhir.model.api.annotation.Child;
|
||||
import ca.uhn.fhir.model.api.annotation.DatatypeDef;
|
||||
|
@ -388,6 +389,5 @@ public class Extension extends BaseExtension implements IBaseExtension<Extension
|
|||
return super.isEmpty() && ca.uhn.fhir.util.ElementUtil.isEmpty(url, value);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -31,6 +31,7 @@ public class ErrorHandlerTest {
|
|||
new ErrorHandlerAdapter().unknownElement(null, null);
|
||||
new ErrorHandlerAdapter().containedResourceWithNoId(null);
|
||||
new ErrorHandlerAdapter().unknownReference(null, null);
|
||||
new ErrorHandlerAdapter().missingRequiredElement(null, null);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
|
@ -56,6 +56,38 @@ public class JsonParserDstu3Test {
|
|||
public void after() {
|
||||
ourCtx.setNarrativeGenerator(null);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* See #414
|
||||
*/
|
||||
@Test
|
||||
public void testParseJsonModifierExtensionWithoutUrl() {
|
||||
//@formatter:off
|
||||
String input =
|
||||
"{\"resourceType\":\"Patient\"," +
|
||||
"\"modifierExtension\":[ {\"valueDateTime\":\"2011-01-02T11:13:15\"} ]" +
|
||||
"}";
|
||||
//@formatter:on
|
||||
|
||||
IParser parser = ourCtx.newJsonParser();
|
||||
parser.setParserErrorHandler(new LenientErrorHandler());
|
||||
Patient parsed = (Patient) parser.parseResource(input);
|
||||
assertEquals(1, parsed.getModifierExtension().size());
|
||||
assertEquals(null, parsed.getModifierExtension().get(0).getUrl());
|
||||
assertEquals("2011-01-02T11:13:15", parsed.getModifierExtension().get(0).getValueAsPrimitive().getValueAsString());
|
||||
|
||||
try {
|
||||
parser = ourCtx.newJsonParser();
|
||||
parser.setParserErrorHandler(new StrictErrorHandler());
|
||||
parser.parseResource(input);
|
||||
fail();
|
||||
} catch (DataFormatException e) {
|
||||
assertEquals("Resource is missing required element 'url' in parent element 'modifierExtension'", e.getMessage());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testParseMissingArray() throws IOException {
|
||||
|
@ -82,6 +114,8 @@ public class JsonParserDstu3Test {
|
|||
assertThat(output, containsString("\"div\": \"<div xmlns=\\\"http://www.w3.org/1999/xhtml\\\">VALUE</div>\""));
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Test
|
||||
public void testEncodeNarrativeShouldIncludeNamespaceWithProcessingInstruction() {
|
||||
|
||||
|
@ -137,6 +171,37 @@ public class JsonParserDstu3Test {
|
|||
assertThat(encode, containsString("\"value\": \"APPID\""));
|
||||
}
|
||||
|
||||
/**
|
||||
* See #414
|
||||
*/
|
||||
@Test
|
||||
public void testParseJsonExtensionWithoutUrl() {
|
||||
//@formatter:off
|
||||
String input =
|
||||
"{\"resourceType\":\"Patient\"," +
|
||||
"\"extension\":[ {\"valueDateTime\":\"2011-01-02T11:13:15\"} ]" +
|
||||
"}";
|
||||
//@formatter:on
|
||||
|
||||
IParser parser = ourCtx.newJsonParser();
|
||||
parser.setParserErrorHandler(new LenientErrorHandler());
|
||||
Patient parsed = (Patient) parser.parseResource(input);
|
||||
assertEquals(1, parsed.getExtension().size());
|
||||
assertEquals(null, parsed.getExtension().get(0).getUrl());
|
||||
assertEquals("2011-01-02T11:13:15", parsed.getExtension().get(0).getValueAsPrimitive().getValueAsString());
|
||||
|
||||
try {
|
||||
parser = ourCtx.newJsonParser();
|
||||
parser.setParserErrorHandler(new StrictErrorHandler());
|
||||
parser.parseResource(input);
|
||||
fail();
|
||||
} catch (DataFormatException e) {
|
||||
assertEquals("Resource is missing required element 'url' in parent element 'extension'", e.getMessage());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* See #344
|
||||
*/
|
||||
|
|
|
@ -23,8 +23,6 @@ import java.io.IOException;
|
|||
import java.io.StringReader;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.ZoneOffset;
|
||||
import java.util.*;
|
||||
|
||||
import org.apache.commons.io.IOUtils;
|
||||
|
@ -78,6 +76,69 @@ public class XmlParserDstu3Test {
|
|||
ourCtx.setNarrativeGenerator(null);
|
||||
}
|
||||
|
||||
/**
|
||||
* See #414
|
||||
*/
|
||||
@Test
|
||||
public void testParseXmlExtensionWithoutUrl() {
|
||||
//@formatter:off
|
||||
String input = "<Patient xmlns=\"http://hl7.org/fhir\">\n" +
|
||||
" <extension>\n" +
|
||||
" <valueDateTime value=\"2011-01-02T11:13:15\"/>\n" +
|
||||
" </extension>\n" +
|
||||
"</Patient>";
|
||||
//@formatter:on
|
||||
|
||||
IParser parser = ourCtx.newXmlParser();
|
||||
parser.setParserErrorHandler(new LenientErrorHandler());
|
||||
Patient parsed = (Patient) parser.parseResource(input);
|
||||
assertEquals(1, parsed.getExtension().size());
|
||||
assertEquals(null, parsed.getExtension().get(0).getUrl());
|
||||
assertEquals("2011-01-02T11:13:15", parsed.getExtension().get(0).getValueAsPrimitive().getValueAsString());
|
||||
|
||||
try {
|
||||
parser = ourCtx.newXmlParser();
|
||||
parser.setParserErrorHandler(new StrictErrorHandler());
|
||||
parser.parseResource(input);
|
||||
fail();
|
||||
} catch (DataFormatException e) {
|
||||
assertEquals("Resource is missing required element 'url' in parent element 'extension'", e.getCause().getMessage());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* See #414
|
||||
*/
|
||||
@Test
|
||||
public void testParseXmlModifierExtensionWithoutUrl() {
|
||||
//@formatter:off
|
||||
String input = "<Patient xmlns=\"http://hl7.org/fhir\">\n" +
|
||||
" <modifierExtension>\n" +
|
||||
" <valueDateTime value=\"2011-01-02T11:13:15\"/>\n" +
|
||||
" </modifierExtension>\n" +
|
||||
"</Patient>";
|
||||
//@formatter:on
|
||||
|
||||
IParser parser = ourCtx.newXmlParser();
|
||||
parser.setParserErrorHandler(new LenientErrorHandler());
|
||||
Patient parsed = (Patient) parser.parseResource(input);
|
||||
assertEquals(1, parsed.getModifierExtension().size());
|
||||
assertEquals(null, parsed.getModifierExtension().get(0).getUrl());
|
||||
assertEquals("2011-01-02T11:13:15", parsed.getModifierExtension().get(0).getValueAsPrimitive().getValueAsString());
|
||||
|
||||
try {
|
||||
parser = ourCtx.newXmlParser();
|
||||
parser.setParserErrorHandler(new StrictErrorHandler());
|
||||
parser.parseResource(input);
|
||||
fail();
|
||||
} catch (DataFormatException e) {
|
||||
assertEquals("Resource is missing required element 'url' in parent element 'modifierExtension'", e.getCause().getMessage());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEncodeChainedContainedResourcer() {
|
||||
Organization gp = new Organization();
|
||||
|
@ -1868,53 +1929,7 @@ public class XmlParserDstu3Test {
|
|||
assertThat(output, containsString("<text><status value=\"generated\"/><div xmlns=\"http://www.w3.org/1999/xhtml\"><div class=\"hapiHeaderText\">John <b>SMITH </b>"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testExceptionWithoutUrl() {
|
||||
//@formatter:off
|
||||
String input =
|
||||
"<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?>" +
|
||||
"<Patient xmlns=\"http://hl7.org/fhir\">" +
|
||||
"<extension>" +
|
||||
"<valueString value=\"FOO\">" +
|
||||
"</extension>" +
|
||||
"<address>" +
|
||||
"<line value=\"FOO\"/>" +
|
||||
"</address>" +
|
||||
"</Patient>";
|
||||
//@formatter:on
|
||||
|
||||
try {
|
||||
ourCtx.newXmlParser().parseResource(Patient.class, input);
|
||||
fail();
|
||||
} catch (DataFormatException e) {
|
||||
assertThat(e.toString(), containsString("Extension element has no 'url' attribute"));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testModifierExceptionWithoutUrl() {
|
||||
//@formatter:off
|
||||
String input =
|
||||
"<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?>" +
|
||||
"<Patient xmlns=\"http://hl7.org/fhir\">" +
|
||||
"<modifierExtension>" +
|
||||
"<valueString value=\"FOO\">" +
|
||||
"</modifierExtension>" +
|
||||
"<address>" +
|
||||
"<line value=\"FOO\"/>" +
|
||||
"</address>" +
|
||||
"</Patient>";
|
||||
//@formatter:on
|
||||
|
||||
try {
|
||||
ourCtx.newXmlParser().parseResource(Patient.class, input);
|
||||
fail();
|
||||
} catch (DataFormatException e) {
|
||||
assertThat(e.toString(), containsString("Extension element has no 'url' attribute"));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testMoreExtensions() throws Exception {
|
||||
|
|
|
@ -128,6 +128,11 @@
|
|||
<![CDATA[<code>MedicationAdministration.medication[x]</code>]]>.
|
||||
Thanks to GitHub user @Crudelus for reporting!
|
||||
</action>
|
||||
<action type="fix" issue="414">
|
||||
Handle parsing an extension without a URL more gracefully. In HAPI FHIR 2.0 this caused
|
||||
a NullPointerException to be thrown. Now it will trigger a warning, or throw a
|
||||
DataFormatException if the StrictErrorHandler is configured on the parser.
|
||||
</action>
|
||||
</release>
|
||||
<release version="2.0" date="2016-08-30">
|
||||
<action type="fix">
|
||||
|
|
Loading…
Reference in New Issue