Handle unexpected extensions when parsing using IParserErrorHandler

This commit is contained in:
jamesagnew 2016-03-02 06:52:46 -05:00
parent 4573b86972
commit 3fd9f9518a
9 changed files with 177 additions and 17 deletions

View File

@ -867,7 +867,7 @@ class ParserState<T> {
ParserState<T>.ExtensionState newState = new ExtensionState(myPreResourceState, ext);
push(newState);
} else {
throw new DataFormatException("Type " + getCurrentElement() + " does not support undeclared extentions, and found an extension with URL: " + theUrlAttr);
logAndSwallowUnexpectedElement("extension");
}
} else {
if (getCurrentElement() instanceof IBaseHasModifierExtensions) {
@ -876,7 +876,7 @@ class ParserState<T> {
ParserState<T>.ExtensionState newState = new ExtensionState(myPreResourceState, ext);
push(newState);
} else {
throw new DataFormatException("Type " + getCurrentElement() + " does not support undeclared extentions, and found an extension with URL: " + theUrlAttr);
logAndSwallowUnexpectedElement("modifierExtension");
}
}
}

View File

@ -76,6 +76,24 @@ public class ElementUtil {
return true;
}
/*
public static <T> void validateAllElementsAreOfTypeOrThrowClassCastExceptionForModelSetter(List<T> theList, Class<T> theType) {
if (theList == null) {
return;
}
for (T next : theList) {
if (next != null && theType.isAssignableFrom(next.getClass()) == false) {
StringBuilder b = new StringBuilder();
b.append("Failed to set invalid value, found element in list of type ");
b.append(next.getClass().getSimpleName());
b.append(" but expected ");
b.append(theType.getName());
throw new ClassCastException(b.toString());
}
}
}
*/
public static boolean isEmpty(List<? extends IBase> theElements) {
if (theElements == null) {
return true;

View File

@ -0,0 +1,40 @@
package ca.uhn.fhir.model.dstu2;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.fail;
import java.util.Arrays;
import java.util.List;
import org.junit.Test;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.model.dstu2.resource.Patient;
public class ModelDstu2Test {
private static FhirContext ourCtx = FhirContext.forDstu2();
/**
* See #304
*/
@SuppressWarnings("rawtypes")
@Test
public void testPopulateWrongGenericType() {
Patient p = new Patient();
List names = Arrays.asList("name");
p.setName(null);
ourCtx.newXmlParser().encodeResourceToString(p);
try {
p.setName(names);
fail();
} catch (ClassCastException e) {
assertEquals("Failed to set invalid value, found element in list of type String but expected ca.uhn.fhir.model.dstu2.composite.HumanNameDt", e.getMessage());
}
}
}

View File

@ -2,7 +2,6 @@ package ca.uhn.fhir.parser;
import static org.hamcrest.Matchers.contains;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.emptyString;
import static org.hamcrest.Matchers.not;
import static org.hamcrest.Matchers.stringContainsInOrder;
import static org.junit.Assert.assertEquals;
@ -11,6 +10,9 @@ import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.fail;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import java.io.IOException;
import java.util.ArrayList;
@ -21,6 +23,8 @@ import org.apache.commons.io.IOUtils;
import org.hamcrest.Matchers;
import org.junit.Assert;
import org.junit.Test;
import org.mockito.ArgumentCaptor;
import org.mockito.Mockito;
import ca.uhn.fhir.context.ConfigurationException;
import ca.uhn.fhir.context.FhirContext;
@ -56,6 +60,7 @@ import ca.uhn.fhir.model.primitive.DateTimeDt;
import ca.uhn.fhir.model.primitive.IdDt;
import ca.uhn.fhir.model.primitive.InstantDt;
import ca.uhn.fhir.model.primitive.StringDt;
import ca.uhn.fhir.parser.IParserErrorHandler.IParseLocation;
import ca.uhn.fhir.rest.server.Constants;
import net.sf.json.JSON;
import net.sf.json.JSONSerializer;
@ -109,10 +114,8 @@ public class JsonParserDstu2Test {
assertThat(enc, Matchers.stringContainsInOrder("{\"resourceType\":\"Patient\",", "\"extension\":[{\"url\":\"http://example.com/extensions#someext\",\"valueDateTime\":\"2011-01-02T11:13:15\"}",
"{\"url\":\"http://example.com#parent\",\"extension\":[{\"url\":\"http://example.com#child\",\"valueString\":\"value1\"},{\"url\":\"http://example.com#child\",\"valueString\":\"value2\"}]}"));
assertThat(enc, Matchers.stringContainsInOrder("\"modifierExtension\":[" + "{" + "\"url\":\"http://example.com/extensions#modext\"," + "\"valueDate\":\"1995-01-02\"" + "}" + "],"));
assertThat(enc,
containsString("\"_given\":[" + "{" + "\"extension\":[" + "{" + "\"url\":\"http://examples.com#givenext\"," + "\"valueString\":\"given\"" + "}" + "]" + "}," + "{" + "\"extension\":[" + "{"
+ "\"url\":\"http://examples.com#givenext_parent\"," + "\"extension\":[" + "{" + "\"url\":\"http://examples.com#givenext_child\"," + "\"valueString\":\"CHILD\"" + "}" + "]" + "}"
+ "]" + "}"));
assertThat(enc, containsString("\"_given\":[" + "{" + "\"extension\":[" + "{" + "\"url\":\"http://examples.com#givenext\"," + "\"valueString\":\"given\"" + "}" + "]" + "}," + "{" + "\"extension\":[" + "{" + "\"url\":\"http://examples.com#givenext_parent\"," + "\"extension\":[" + "{"
+ "\"url\":\"http://examples.com#givenext_child\"," + "\"valueString\":\"CHILD\"" + "}" + "]" + "}" + "]" + "}"));
/*
* Now parse this back
@ -207,7 +210,7 @@ public class JsonParserDstu2Test {
assertEquals(new Tag("scheme1", "term1", "label1"), tagList.get(0));
assertEquals(new Tag("scheme2", "term2", "label2"), tagList.get(1));
}
@Test
public void testEncodeAndParseSecurityLabels() {
Patient p = new Patient();
@ -333,7 +336,7 @@ public class JsonParserDstu2Test {
Patient p = new Patient();
p.setId(new IdDt("urn:uuid:42795ed8-041f-4ebf-b6f4-78ef6f64c2f2"));
p.addIdentifier().setSystem("ACME");
String actual = ourCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(p);
assertThat(actual, not(containsString("78ef6f64c2f2")));
}
@ -431,8 +434,7 @@ public class JsonParserDstu2Test {
ourLog.info(encoded);
assertThat(encoded, containsString("Patient"));
assertThat(encoded, stringContainsInOrder("\"tag\"", "\"system\":\"foo\",", "\"code\":\"bar\"", "\"system\":\"" + Constants.TAG_SUBSETTED_SYSTEM + "\",",
"\"code\":\"" + Constants.TAG_SUBSETTED_CODE + "\","));
assertThat(encoded, stringContainsInOrder("\"tag\"", "\"system\":\"foo\",", "\"code\":\"bar\"", "\"system\":\"" + Constants.TAG_SUBSETTED_SYSTEM + "\",", "\"code\":\"" + Constants.TAG_SUBSETTED_CODE + "\","));
assertThat(encoded, not(containsString("THE DIV")));
assertThat(encoded, containsString("family"));
assertThat(encoded, not(containsString("maritalStatus")));
@ -453,8 +455,7 @@ public class JsonParserDstu2Test {
String enc = ourCtx.newJsonParser().encodeResourceToString(pt);
ourLog.info(enc);
assertEquals("{\"resourceType\":\"Patient\",\"meta\":{\"tag\":[{\"system\":\"scheme\",\"code\":\"term\",\"display\":\"display\"}]},\"identifier\":[{\"system\":\"sys\",\"value\":\"val\"}]}",
enc);
assertEquals("{\"resourceType\":\"Patient\",\"meta\":{\"tag\":[{\"system\":\"scheme\",\"code\":\"term\",\"display\":\"display\"}]},\"identifier\":[{\"system\":\"sys\",\"value\":\"val\"}]}", enc);
}
@ -537,11 +538,11 @@ public class JsonParserDstu2Test {
public void testNamespacePreservationParse() throws Exception {
String input = "{\"resourceType\":\"Patient\",\"text\":{\"div\":\"<xhtml:div xmlns:xhtml=\\\"http://www.w3.org/1999/xhtml\\\"><xhtml:img src=\\\"foo\\\"/>@fhirabend</xhtml:div>\"}}";
Patient parsed = ourCtx.newJsonParser().parseResource(Patient.class, input);
assertEquals("<xhtml:div xmlns:xhtml=\"http://www.w3.org/1999/xhtml\"><xhtml:img src=\"foo\"/>@fhirabend</xhtml:div>", parsed.getText().getDiv().getValueAsString());
String encoded = ourCtx.newXmlParser().encodeResourceToString(parsed);
assertEquals("<Patient xmlns=\"http://hl7.org/fhir\"><text><xhtml:div xmlns:xhtml=\"http://www.w3.org/1999/xhtml\"><xhtml:img src=\"foo\"/>@fhirabend</xhtml:div></text></Patient>",encoded);
assertEquals("<Patient xmlns=\"http://hl7.org/fhir\"><text><xhtml:div xmlns:xhtml=\"http://www.w3.org/1999/xhtml\"><xhtml:img src=\"foo\"/>@fhirabend</xhtml:div></text></Patient>", encoded);
}
@Test
@ -1067,6 +1068,30 @@ public class JsonParserDstu2Test {
}
}
@Test
public void testParseWithExtensions() throws Exception {
String input = IOUtils.toString(getClass().getResourceAsStream("/patient1.json"));
IParser parser = ourCtx.newJsonParser();
IParserErrorHandler peh = mock(IParserErrorHandler.class);
parser.setParserErrorHandler(peh);
Patient p = parser.parseResource(Patient.class, input);
ArgumentCaptor<String> capt = ArgumentCaptor.forClass(String.class);
verify(peh, times(4)).unknownElement(Mockito.isNull(IParseLocation.class), capt.capture());
//@formatter:off
List<String> strings = capt.getAllValues();
assertThat(strings, contains(
"extension",
"extension",
"modifierExtension",
"modifierExtension"
));
//@formatter:off
assertEquals("Smith", p.getName().get(0).getGiven().get(0).getValue());
}
@Test
public void testParseWithWrongTypeObjectShouldBeArray() throws Exception {
String input = IOUtils.toString(getClass().getResourceAsStream("/invalid_metadata.json"));

View File

@ -97,6 +97,7 @@ public class XmlParserDstu2Test {
private static final FhirContext ourCtx = FhirContext.forDstu2();
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(XmlParserDstu2Test.class);
@Test
public void testBundleWithBinary() {
//@formatter:off

View File

@ -0,0 +1,35 @@
{
"id": "73b551fb-46f5-4fb8-b735-2399344e9717",
"meta": {
"extension": [
{
"url": "fhir-request-method",
"valueString": "POST"
},
{
"url": "fhir-request-uri",
"valueUri": "Patient"
}
],
"modifierExtension": [
{
"url": "fhir-request-method",
"valueString": "POST"
},
{
"url": "fhir-request-uri",
"valueUri": "Patient"
}
],
"versionId": "01e5253d-d258-494c-8d8e-f22ad6d8f19b",
"lastUpdated": "2016-02-20T11:01:56.155Z"
},
"name": [
{
"given": [
"Smith"
]
}
],
"resourceType": "Patient"
}

View File

@ -0,0 +1,33 @@
package ca.uhn.fhir.model;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.fail;
import java.util.Arrays;
import java.util.List;
import org.hl7.fhir.dstu3.model.Patient;
import org.junit.Test;
public class ModelDstu3Test {
/**
* See #304
*/
@SuppressWarnings("rawtypes")
@Test
public void testPopulateWrongGenericType() {
Patient p = new Patient();
List names = Arrays.asList("name");
p.setName(null);
try {
p.setName(names);
fail();
} catch (ClassCastException e) {
assertEquals("Failed to set invalid value, found element in list of type String but expected ca.uhn.fhir.model.dstu2.composite.HumanNameDt", e.getMessage());
}
}
}

View File

@ -123,7 +123,9 @@ public abstract class Child extends BaseElement {
public String getSingleType() {
String retVal;
String elemName = this.getType().get(0);
elemName = elemName.substring(0, 1).toUpperCase() + elemName.substring(1);
if (elemName.startsWith("ca.") == false) {
elemName = elemName.substring(0, 1).toUpperCase() + elemName.substring(1);
}
// if (this instanceof ResourceBlock) {
retVal = (elemName);
// } else {

View File

@ -158,6 +158,12 @@
buttom will no longer show a "loading" spinner, but there doesn't seem to
be another way of fixing this. Thanks to Mark Scrimshire for reporting!
</action>
<action type="fix">
Extensions found while parsing an object that doesn't support extensions are now
reported using the IParserErrorHandler framework in the same way that
other similar errors are handled. This allows the parser to be more lenient
when needed.
</action>
</release>
<release version="1.4" date="2016-02-04">
<action type="add">