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); ParserState<T>.ExtensionState newState = new ExtensionState(myPreResourceState, ext);
push(newState); push(newState);
} else { } else {
throw new DataFormatException("Type " + getCurrentElement() + " does not support undeclared extentions, and found an extension with URL: " + theUrlAttr); logAndSwallowUnexpectedElement("extension");
} }
} else { } else {
if (getCurrentElement() instanceof IBaseHasModifierExtensions) { if (getCurrentElement() instanceof IBaseHasModifierExtensions) {
@ -876,7 +876,7 @@ class ParserState<T> {
ParserState<T>.ExtensionState newState = new ExtensionState(myPreResourceState, ext); ParserState<T>.ExtensionState newState = new ExtensionState(myPreResourceState, ext);
push(newState); push(newState);
} else { } 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; 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) { public static boolean isEmpty(List<? extends IBase> theElements) {
if (theElements == null) { if (theElements == null) {
return true; 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.contains;
import static org.hamcrest.Matchers.containsString; import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.emptyString;
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.assertEquals;
@ -11,6 +10,9 @@ import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertSame; import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertThat; import static org.junit.Assert.assertThat;
import static org.junit.Assert.fail; 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.io.IOException;
import java.util.ArrayList; import java.util.ArrayList;
@ -21,6 +23,8 @@ import org.apache.commons.io.IOUtils;
import org.hamcrest.Matchers; import org.hamcrest.Matchers;
import org.junit.Assert; import org.junit.Assert;
import org.junit.Test; import org.junit.Test;
import org.mockito.ArgumentCaptor;
import org.mockito.Mockito;
import ca.uhn.fhir.context.ConfigurationException; import ca.uhn.fhir.context.ConfigurationException;
import ca.uhn.fhir.context.FhirContext; 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.IdDt;
import ca.uhn.fhir.model.primitive.InstantDt; import ca.uhn.fhir.model.primitive.InstantDt;
import ca.uhn.fhir.model.primitive.StringDt; import ca.uhn.fhir.model.primitive.StringDt;
import ca.uhn.fhir.parser.IParserErrorHandler.IParseLocation;
import ca.uhn.fhir.rest.server.Constants; import ca.uhn.fhir.rest.server.Constants;
import net.sf.json.JSON; import net.sf.json.JSON;
import net.sf.json.JSONSerializer; 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\"}", 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\"}]}")); "{\"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, Matchers.stringContainsInOrder("\"modifierExtension\":[" + "{" + "\"url\":\"http://example.com/extensions#modext\"," + "\"valueDate\":\"1995-01-02\"" + "}" + "],"));
assertThat(enc, assertThat(enc, containsString("\"_given\":[" + "{" + "\"extension\":[" + "{" + "\"url\":\"http://examples.com#givenext\"," + "\"valueString\":\"given\"" + "}" + "]" + "}," + "{" + "\"extension\":[" + "{" + "\"url\":\"http://examples.com#givenext_parent\"," + "\"extension\":[" + "{"
containsString("\"_given\":[" + "{" + "\"extension\":[" + "{" + "\"url\":\"http://examples.com#givenext\"," + "\"valueString\":\"given\"" + "}" + "]" + "}," + "{" + "\"extension\":[" + "{" + "\"url\":\"http://examples.com#givenext_child\"," + "\"valueString\":\"CHILD\"" + "}" + "]" + "}" + "]" + "}"));
+ "\"url\":\"http://examples.com#givenext_parent\"," + "\"extension\":[" + "{" + "\"url\":\"http://examples.com#givenext_child\"," + "\"valueString\":\"CHILD\"" + "}" + "]" + "}"
+ "]" + "}"));
/* /*
* Now parse this back * Now parse this back
@ -431,8 +434,7 @@ public class JsonParserDstu2Test {
ourLog.info(encoded); ourLog.info(encoded);
assertThat(encoded, containsString("Patient")); assertThat(encoded, containsString("Patient"));
assertThat(encoded, stringContainsInOrder("\"tag\"", "\"system\":\"foo\",", "\"code\":\"bar\"", "\"system\":\"" + Constants.TAG_SUBSETTED_SYSTEM + "\",", assertThat(encoded, stringContainsInOrder("\"tag\"", "\"system\":\"foo\",", "\"code\":\"bar\"", "\"system\":\"" + Constants.TAG_SUBSETTED_SYSTEM + "\",", "\"code\":\"" + Constants.TAG_SUBSETTED_CODE + "\","));
"\"code\":\"" + Constants.TAG_SUBSETTED_CODE + "\","));
assertThat(encoded, not(containsString("THE DIV"))); assertThat(encoded, not(containsString("THE DIV")));
assertThat(encoded, containsString("family")); assertThat(encoded, containsString("family"));
assertThat(encoded, not(containsString("maritalStatus"))); assertThat(encoded, not(containsString("maritalStatus")));
@ -453,8 +455,7 @@ public class JsonParserDstu2Test {
String enc = ourCtx.newJsonParser().encodeResourceToString(pt); String enc = ourCtx.newJsonParser().encodeResourceToString(pt);
ourLog.info(enc); ourLog.info(enc);
assertEquals("{\"resourceType\":\"Patient\",\"meta\":{\"tag\":[{\"system\":\"scheme\",\"code\":\"term\",\"display\":\"display\"}]},\"identifier\":[{\"system\":\"sys\",\"value\":\"val\"}]}", assertEquals("{\"resourceType\":\"Patient\",\"meta\":{\"tag\":[{\"system\":\"scheme\",\"code\":\"term\",\"display\":\"display\"}]},\"identifier\":[{\"system\":\"sys\",\"value\":\"val\"}]}", enc);
enc);
} }
@ -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 @Test
public void testParseWithWrongTypeObjectShouldBeArray() throws Exception { public void testParseWithWrongTypeObjectShouldBeArray() throws Exception {
String input = IOUtils.toString(getClass().getResourceAsStream("/invalid_metadata.json")); 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 FhirContext ourCtx = FhirContext.forDstu2();
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(XmlParserDstu2Test.class); private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(XmlParserDstu2Test.class);
@Test @Test
public void testBundleWithBinary() { public void testBundleWithBinary() {
//@formatter:off //@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() { public String getSingleType() {
String retVal; String retVal;
String elemName = this.getType().get(0); String elemName = this.getType().get(0);
if (elemName.startsWith("ca.") == false) {
elemName = elemName.substring(0, 1).toUpperCase() + elemName.substring(1); elemName = elemName.substring(0, 1).toUpperCase() + elemName.substring(1);
}
// if (this instanceof ResourceBlock) { // if (this instanceof ResourceBlock) {
retVal = (elemName); retVal = (elemName);
// } else { // } else {

View File

@ -158,6 +158,12 @@
buttom will no longer show a "loading" spinner, but there doesn't seem to 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! be another way of fixing this. Thanks to Mark Scrimshire for reporting!
</action> </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>
<release version="1.4" date="2016-02-04"> <release version="1.4" date="2016-02-04">
<action type="add"> <action type="add">