mirror of
https://github.com/hapifhir/hapi-fhir.git
synced 2025-02-16 18:05:19 +00:00
Fix #516 - Handle STU3 invalid enum values with an appropriate exception
This commit is contained in:
parent
1fba4ff265
commit
ee63bbea74
@ -13,69 +13,68 @@ import ca.uhn.fhir.rest.param.StringParam;
|
|||||||
import ca.uhn.fhir.rest.server.IBundleProvider;
|
import ca.uhn.fhir.rest.server.IBundleProvider;
|
||||||
import ca.uhn.fhir.rest.server.IResourceProvider;
|
import ca.uhn.fhir.rest.server.IResourceProvider;
|
||||||
|
|
||||||
|
|
||||||
@SuppressWarnings("null")
|
@SuppressWarnings("null")
|
||||||
//START SNIPPET: provider
|
// START SNIPPET: provider
|
||||||
public class PagingPatientProvider implements IResourceProvider {
|
public class PagingPatientProvider implements IResourceProvider {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Search for Patient resources matching a given family name
|
* Search for Patient resources matching a given family name
|
||||||
*/
|
*/
|
||||||
@Search
|
@Search
|
||||||
public IBundleProvider search(@RequiredParam(name = Patient.SP_FAMILY) StringParam theFamily) {
|
public IBundleProvider search(@RequiredParam(name = Patient.SP_FAMILY) StringParam theFamily) {
|
||||||
final InstantDt searchTime = InstantDt.withCurrentTime();
|
final InstantDt searchTime = InstantDt.withCurrentTime();
|
||||||
|
|
||||||
/*
|
/**
|
||||||
* First, we'll search the database for a set of database row IDs that
|
* First, we'll search the database for a set of database row IDs that
|
||||||
* match the given search criteria. That way we can keep just the
|
* match the given search criteria. That way we can keep just the row IDs
|
||||||
* row IDs around, and load the actual resources on demand later
|
* around, and load the actual resources on demand later as the client
|
||||||
* as the client pages through them.
|
* pages through them.
|
||||||
*/
|
*/
|
||||||
final List<Long> matchingResourceIds = null; // <-- implement this
|
final List<Long> matchingResourceIds = null; // <-- implement this
|
||||||
|
|
||||||
/*
|
/**
|
||||||
* Return a bundle provider which can page through the IDs and
|
* Return a bundle provider which can page through the IDs and return the
|
||||||
* return the resources that go with them.
|
* resources that go with them.
|
||||||
*/
|
*/
|
||||||
return new IBundleProvider() {
|
return new IBundleProvider() {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int size() {
|
public int size() {
|
||||||
return matchingResourceIds.size();
|
return matchingResourceIds.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<IBaseResource> getResources(int theFromIndex, int theToIndex) {
|
public List<IBaseResource> getResources(int theFromIndex, int theToIndex) {
|
||||||
int end = Math.max(theToIndex, matchingResourceIds.size() - 1);
|
int end = Math.max(theToIndex, matchingResourceIds.size() - 1);
|
||||||
List<Long> idsToReturn = matchingResourceIds.subList(theFromIndex, end);
|
List<Long> idsToReturn = matchingResourceIds.subList(theFromIndex, end);
|
||||||
return loadResourcesByIds(idsToReturn);
|
return loadResourcesByIds(idsToReturn);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public InstantDt getPublished() {
|
public InstantDt getPublished() {
|
||||||
return searchTime;
|
return searchTime;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Integer preferredPageSize() {
|
public Integer preferredPageSize() {
|
||||||
// Typically this method just returns null
|
// Typically this method just returns null
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Load a list of patient resources given their IDs
|
* Load a list of patient resources given their IDs
|
||||||
*/
|
*/
|
||||||
private List<IBaseResource> loadResourcesByIds(List<Long> theIdsToReturn) {
|
private List<IBaseResource> loadResourcesByIds(List<Long> theIdsToReturn) {
|
||||||
// .. implement this search against the database ..
|
// .. implement this search against the database ..
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Class<? extends IResource> getResourceType() {
|
public Class<? extends IResource> getResourceType() {
|
||||||
return Patient.class;
|
return Patient.class;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
//END SNIPPET: provider
|
// END SNIPPET: provider
|
||||||
|
@ -1,5 +1,8 @@
|
|||||||
package ca.uhn.fhir.parser;
|
package ca.uhn.fhir.parser;
|
||||||
|
|
||||||
|
import static org.apache.commons.lang3.StringUtils.isBlank;
|
||||||
|
import static org.apache.commons.lang3.StringUtils.isNotBlank;
|
||||||
|
|
||||||
import ca.uhn.fhir.context.FhirContext;
|
import ca.uhn.fhir.context.FhirContext;
|
||||||
import ca.uhn.fhir.parser.json.JsonLikeValue.ValueType;
|
import ca.uhn.fhir.parser.json.JsonLikeValue.ValueType;
|
||||||
|
|
||||||
@ -24,7 +27,13 @@ import ca.uhn.fhir.parser.json.JsonLikeValue.ValueType;
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The default error handler, which logs issues but does not abort parsing
|
* The default error handler, which logs issues but does not abort parsing, with only one exception:
|
||||||
|
* <p>
|
||||||
|
* The {@link #invalidValue(ca.uhn.fhir.parser.IParserErrorHandler.IParseLocation, String, String)}
|
||||||
|
* method will throw a {@link DataFormatException} by default since ignoring this type of error
|
||||||
|
* can lead to data loss (since invalid values are silently ignored). See
|
||||||
|
* {@link #setErrorOnInvalidValue(boolean)} for information on this.
|
||||||
|
* </p>
|
||||||
*
|
*
|
||||||
* @see IParser#setParserErrorHandler(IParserErrorHandler)
|
* @see IParser#setParserErrorHandler(IParserErrorHandler)
|
||||||
* @see FhirContext#setParserErrorHandler(IParserErrorHandler)
|
* @see FhirContext#setParserErrorHandler(IParserErrorHandler)
|
||||||
@ -32,6 +41,8 @@ import ca.uhn.fhir.parser.json.JsonLikeValue.ValueType;
|
|||||||
public class LenientErrorHandler implements IParserErrorHandler {
|
public class LenientErrorHandler implements IParserErrorHandler {
|
||||||
|
|
||||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(LenientErrorHandler.class);
|
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(LenientErrorHandler.class);
|
||||||
|
private static final StrictErrorHandler STRICT_ERROR_HANDLER = new StrictErrorHandler();
|
||||||
|
private boolean myErrorOnInvalidValue = true;
|
||||||
private boolean myLogErrors;
|
private boolean myLogErrors;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -67,11 +78,30 @@ public class LenientErrorHandler implements IParserErrorHandler {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void invalidValue(IParseLocation theLocation, String theValue, String theError) {
|
public void invalidValue(IParseLocation theLocation, String theValue, String theError) {
|
||||||
if (myLogErrors) {
|
if (isBlank(theValue) || myErrorOnInvalidValue == false) {
|
||||||
ourLog.warn("Invalid attribute value \"{}\": {}", theValue, theError);
|
if (myLogErrors) {
|
||||||
|
ourLog.warn("Invalid attribute value \"{}\": {}", theValue, theError);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
STRICT_ERROR_HANDLER.invalidValue(theLocation, theValue, theError);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If set to <code>false</code> (default is <code>true</code>) invalid values will be logged. By
|
||||||
|
* default invalid attribute values cause this error handler to throw a {@link DataFormatException} (unlike
|
||||||
|
* other methods in this class which default to simply logging errors).
|
||||||
|
* <p>
|
||||||
|
* Note that empty values (e.g. <code>""</code>) will not lead to an error when this is set to
|
||||||
|
* <code>true</code>, only invalid values (e.g. a gender code of <code>foo</code>)
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @see #setErrorOnInvalidValue(boolean)
|
||||||
|
*/
|
||||||
|
public boolean isErrorOnInvalidValue() {
|
||||||
|
return myErrorOnInvalidValue;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void missingRequiredElement(IParseLocation theLocation, String theElementName) {
|
public void missingRequiredElement(IParseLocation theLocation, String theElementName) {
|
||||||
if (myLogErrors) {
|
if (myLogErrors) {
|
||||||
@ -79,6 +109,22 @@ public class LenientErrorHandler implements IParserErrorHandler {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If set to <code>false</code> (default is <code>true</code>) invalid values will be logged. By
|
||||||
|
* default invalid attribute values cause this error handler to throw a {@link DataFormatException} (unlike
|
||||||
|
* other methods in this class which default to simply logging errors).
|
||||||
|
* <p>
|
||||||
|
* Note that empty values (e.g. <code>""</code>) will not lead to an error when this is set to
|
||||||
|
* <code>true</code>, only invalid values (e.g. a gender code of <code>foo</code>)
|
||||||
|
* </p>
|
||||||
|
* @return Returns a reference to <code>this</code> for easy method chaining
|
||||||
|
* @see #isErrorOnInvalidValue()
|
||||||
|
*/
|
||||||
|
public LenientErrorHandler setErrorOnInvalidValue(boolean theErrorOnInvalidValue) {
|
||||||
|
myErrorOnInvalidValue = theErrorOnInvalidValue;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void unexpectedRepeatingElement(IParseLocation theLocation, String theElementName) {
|
public void unexpectedRepeatingElement(IParseLocation theLocation, String theElementName) {
|
||||||
if (myLogErrors) {
|
if (myLogErrors) {
|
||||||
|
@ -2311,6 +2311,8 @@ class ParserState<T> {
|
|||||||
} else {
|
} else {
|
||||||
try {
|
try {
|
||||||
myInstance.setValueAsString(theValue);
|
myInstance.setValueAsString(theValue);
|
||||||
|
} catch (DataFormatException e) {
|
||||||
|
myErrorHandler.invalidValue(null, theValue, e.getMessage());
|
||||||
} catch (IllegalArgumentException e) {
|
} catch (IllegalArgumentException e) {
|
||||||
myErrorHandler.invalidValue(null, theValue, e.getMessage());
|
myErrorHandler.invalidValue(null, theValue, e.getMessage());
|
||||||
}
|
}
|
||||||
|
@ -25,6 +25,8 @@ import org.hl7.fhir.instance.model.api.IBaseResource;
|
|||||||
import ca.uhn.fhir.context.FhirContext;
|
import ca.uhn.fhir.context.FhirContext;
|
||||||
import ca.uhn.fhir.model.api.Bundle;
|
import ca.uhn.fhir.model.api.Bundle;
|
||||||
import ca.uhn.fhir.model.api.IResource;
|
import ca.uhn.fhir.model.api.IResource;
|
||||||
|
import ca.uhn.fhir.parser.IParser;
|
||||||
|
import ca.uhn.fhir.parser.LenientErrorHandler;
|
||||||
import ca.uhn.fhir.rest.method.MethodUtil;
|
import ca.uhn.fhir.rest.method.MethodUtil;
|
||||||
import ca.uhn.fhir.rest.server.EncodingEnum;
|
import ca.uhn.fhir.rest.server.EncodingEnum;
|
||||||
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
|
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
|
||||||
@ -146,7 +148,11 @@ public class ValidationContext<T> extends BaseValidationContext<T> implements IV
|
|||||||
@Override
|
@Override
|
||||||
public IBaseResource getResource() {
|
public IBaseResource getResource() {
|
||||||
if (myParsed == null) {
|
if (myParsed == null) {
|
||||||
myParsed = getResourceAsStringEncoding().newParser(getFhirContext()).parseResource(getResourceAsString());
|
IParser parser = getResourceAsStringEncoding().newParser(getFhirContext());
|
||||||
|
LenientErrorHandler errorHandler = new LenientErrorHandler();
|
||||||
|
errorHandler.setErrorOnInvalidValue(false);
|
||||||
|
parser.setParserErrorHandler(errorHandler);
|
||||||
|
myParsed = parser.parseResource(getResourceAsString());
|
||||||
}
|
}
|
||||||
return myParsed;
|
return myParsed;
|
||||||
}
|
}
|
||||||
|
@ -11,7 +11,13 @@ import static org.junit.Assert.assertThat;
|
|||||||
import static org.junit.Assert.fail;
|
import static org.junit.Assert.fail;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
|
||||||
|
import org.apache.commons.io.IOUtils;
|
||||||
|
import org.apache.http.client.methods.CloseableHttpResponse;
|
||||||
|
import org.apache.http.client.methods.HttpPost;
|
||||||
|
import org.apache.http.entity.ContentType;
|
||||||
|
import org.apache.http.entity.StringEntity;
|
||||||
import org.hl7.fhir.dstu3.model.BooleanType;
|
import org.hl7.fhir.dstu3.model.BooleanType;
|
||||||
import org.hl7.fhir.dstu3.model.CodeSystem;
|
import org.hl7.fhir.dstu3.model.CodeSystem;
|
||||||
import org.hl7.fhir.dstu3.model.CodeType;
|
import org.hl7.fhir.dstu3.model.CodeType;
|
||||||
@ -34,6 +40,7 @@ import ca.uhn.fhir.jpa.entity.ResourceTable;
|
|||||||
import ca.uhn.fhir.jpa.entity.TermCodeSystemVersion;
|
import ca.uhn.fhir.jpa.entity.TermCodeSystemVersion;
|
||||||
import ca.uhn.fhir.jpa.entity.TermConcept;
|
import ca.uhn.fhir.jpa.entity.TermConcept;
|
||||||
import ca.uhn.fhir.jpa.entity.TermConceptParentChildLink.RelationshipTypeEnum;
|
import ca.uhn.fhir.jpa.entity.TermConceptParentChildLink.RelationshipTypeEnum;
|
||||||
|
import ca.uhn.fhir.rest.server.Constants;
|
||||||
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
|
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
|
||||||
import ca.uhn.fhir.util.TestUtil;
|
import ca.uhn.fhir.util.TestUtil;
|
||||||
|
|
||||||
@ -54,6 +61,30 @@ public class ResourceProviderDstu3ValueSetTest extends BaseResourceProviderDstu3
|
|||||||
myExtensionalVsId = myValueSetDao.create(upload, mySrd).getId().toUnqualifiedVersionless();
|
myExtensionalVsId = myValueSetDao.create(upload, mySrd).getId().toUnqualifiedVersionless();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* #516
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testInvalidFilter() throws Exception {
|
||||||
|
String string = IOUtils.toString(getClass().getResourceAsStream("/bug_516_invalid_expansion.json"), StandardCharsets.UTF_8);
|
||||||
|
HttpPost post = new HttpPost(ourServerBase+"/ValueSet/%24expand");
|
||||||
|
post.setEntity(new StringEntity(string, ContentType.parse(Constants.CT_FHIR_JSON_NEW)));
|
||||||
|
|
||||||
|
CloseableHttpResponse resp = ourHttpClient.execute(post);
|
||||||
|
try {
|
||||||
|
|
||||||
|
String respString = IOUtils.toString(resp.getEntity().getContent(), StandardCharsets.UTF_8);
|
||||||
|
ourLog.info(respString);
|
||||||
|
|
||||||
|
ourLog.info(resp.toString());
|
||||||
|
|
||||||
|
assertEquals(400, resp.getStatusLine().getStatusCode());
|
||||||
|
assertThat(respString, containsString("Unknown FilterOperator code 'n'"));
|
||||||
|
|
||||||
|
}finally {
|
||||||
|
IOUtils.closeQuietly(resp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private CodeSystem createExternalCs() {
|
private CodeSystem createExternalCs() {
|
||||||
CodeSystem codeSystem = new CodeSystem();
|
CodeSystem codeSystem = new CodeSystem();
|
||||||
|
@ -0,0 +1,47 @@
|
|||||||
|
{
|
||||||
|
"resourceType": "ValueSet",
|
||||||
|
"url": "http://sample/ValueSet/education-levels",
|
||||||
|
"version": "1",
|
||||||
|
"name": "Education Levels",
|
||||||
|
"status": "draft",
|
||||||
|
"compose": {
|
||||||
|
"include": [
|
||||||
|
{
|
||||||
|
"filter": [
|
||||||
|
{
|
||||||
|
"property": "n",
|
||||||
|
"op": "n",
|
||||||
|
"value": "365460000"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"system": "http://snomed.info/sct"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"exclude": [
|
||||||
|
{
|
||||||
|
"concept": [
|
||||||
|
{
|
||||||
|
"code": "224298008"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"code": "365460000"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"code": "473462005"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"code": "424587006"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"system": "http://snomed.info/sct"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"description": "A\nselection of Education Levels",
|
||||||
|
"text": {
|
||||||
|
"status": "generated",
|
||||||
|
"div": "<div\nxmlns=\"http://www.w3.org/1999/xhtml\"><h2>Education\nLevels</h2><tt>http://csiro.au/ValueSet/education-levels</tt><p>A selection of\nEducation Levels</p></div>"
|
||||||
|
},
|
||||||
|
"experimental": true,
|
||||||
|
"date": "2016-07-26"
|
||||||
|
}
|
@ -1019,14 +1019,12 @@
|
|||||||
<content type="text/xml">
|
<content type="text/xml">
|
||||||
<Patient xmlns="http://hl7.org/fhir">
|
<Patient xmlns="http://hl7.org/fhir">
|
||||||
<identifier>
|
<identifier>
|
||||||
<system value=""/>
|
|
||||||
<value value="NEED"/>
|
<value value="NEED"/>
|
||||||
<assigner>
|
<assigner>
|
||||||
<display value="FHIR"/>
|
<display value="FHIR"/>
|
||||||
</assigner>
|
</assigner>
|
||||||
</identifier>
|
</identifier>
|
||||||
<identifier>
|
<identifier>
|
||||||
<system value=""/>
|
|
||||||
<value value="E3289"/>
|
<value value="E3289"/>
|
||||||
<assigner>
|
<assigner>
|
||||||
<display value="EPIC"/>
|
<display value="EPIC"/>
|
||||||
|
@ -27,6 +27,7 @@ import ca.uhn.fhir.model.api.IResource;
|
|||||||
import ca.uhn.fhir.model.dstu2.composite.MetaDt;
|
import ca.uhn.fhir.model.dstu2.composite.MetaDt;
|
||||||
import ca.uhn.fhir.model.dstu2.resource.Bundle;
|
import ca.uhn.fhir.model.dstu2.resource.Bundle;
|
||||||
import ca.uhn.fhir.narrative.DefaultThymeleafNarrativeGenerator;
|
import ca.uhn.fhir.narrative.DefaultThymeleafNarrativeGenerator;
|
||||||
|
import ca.uhn.fhir.parser.StrictErrorHandler;
|
||||||
import ca.uhn.fhir.rest.server.ETagSupportEnum;
|
import ca.uhn.fhir.rest.server.ETagSupportEnum;
|
||||||
import ca.uhn.fhir.rest.server.EncodingEnum;
|
import ca.uhn.fhir.rest.server.EncodingEnum;
|
||||||
import ca.uhn.fhir.rest.server.IResourceProvider;
|
import ca.uhn.fhir.rest.server.IResourceProvider;
|
||||||
@ -49,10 +50,13 @@ public class JpaServerDemo extends RestfulServer {
|
|||||||
* We want to support FHIR DSTU2 format. This means that the server
|
* We want to support FHIR DSTU2 format. This means that the server
|
||||||
* will use the DSTU2 bundle format and other DSTU2 encoding changes.
|
* will use the DSTU2 bundle format and other DSTU2 encoding changes.
|
||||||
*
|
*
|
||||||
* If you want to use DSTU1 instead, change the following line, and change the 2 occurrences of dstu2 in web.xml to dstu1
|
* If you want to use DSTU1 instead, change the following line, and
|
||||||
|
* change the 2 occurrences of dstu2 in web.xml to dstu1
|
||||||
*/
|
*/
|
||||||
FhirVersionEnum fhirVersion = FhirVersionEnum.DSTU2;
|
FhirVersionEnum fhirVersion = FhirVersionEnum.DSTU2;
|
||||||
setFhirContext(new FhirContext(fhirVersion));
|
FhirContext context = new FhirContext(fhirVersion);
|
||||||
|
|
||||||
|
setFhirContext(context);
|
||||||
|
|
||||||
// Get the spring context from the web container (it's declared in web.xml)
|
// Get the spring context from the web container (it's declared in web.xml)
|
||||||
myAppCtx = ContextLoaderListener.getCurrentWebApplicationContext();
|
myAppCtx = ContextLoaderListener.getCurrentWebApplicationContext();
|
||||||
|
@ -20,6 +20,8 @@ import ca.uhn.fhir.model.dstu.resource.Patient;
|
|||||||
import ca.uhn.fhir.model.dstu.valueset.ContactSystemEnum;
|
import ca.uhn.fhir.model.dstu.valueset.ContactSystemEnum;
|
||||||
import ca.uhn.fhir.model.primitive.DateTimeDt;
|
import ca.uhn.fhir.model.primitive.DateTimeDt;
|
||||||
import ca.uhn.fhir.parser.DataFormatException;
|
import ca.uhn.fhir.parser.DataFormatException;
|
||||||
|
import ca.uhn.fhir.parser.IParser;
|
||||||
|
import ca.uhn.fhir.parser.StrictErrorHandler;
|
||||||
import ca.uhn.fhir.util.TestUtil;
|
import ca.uhn.fhir.util.TestUtil;
|
||||||
|
|
||||||
public class ResourceValidatorTest {
|
public class ResourceValidatorTest {
|
||||||
@ -72,23 +74,34 @@ public class ResourceValidatorTest {
|
|||||||
/**
|
/**
|
||||||
* See issue #50
|
* See issue #50
|
||||||
*/
|
*/
|
||||||
@Test(expected=DataFormatException.class)
|
@Test()
|
||||||
public void testOutOfBoundsDate() {
|
public void testOutOfBoundsDate() {
|
||||||
Patient p = new Patient();
|
Patient p = new Patient();
|
||||||
p.setBirthDate(new DateTimeDt("2000-12-31"));
|
p.setBirthDate(new DateTimeDt("2000-12-31"));
|
||||||
|
|
||||||
// Put in an invalid date
|
// Put in an invalid date
|
||||||
String encoded = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(p).replace("2000-12-31", "2000-15-31");
|
IParser parser = ourCtx.newXmlParser();
|
||||||
|
parser.setParserErrorHandler(new StrictErrorHandler());
|
||||||
|
|
||||||
|
String encoded = parser.setPrettyPrint(true).encodeResourceToString(p).replace("2000-12-31", "2000-15-31");
|
||||||
ourLog.info(encoded);
|
ourLog.info(encoded);
|
||||||
|
|
||||||
assertThat(encoded, StringContains.containsString("2000-15-31"));
|
assertThat(encoded, StringContains.containsString("2000-15-31"));
|
||||||
|
|
||||||
ValidationResult result = ourCtx.newValidator().validateWithResult(encoded);
|
FhirValidator validator = ourCtx.newValidator();
|
||||||
String resultString = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(result.toOperationOutcome());
|
ValidationResult result = validator.validateWithResult(encoded);
|
||||||
|
String resultString = parser.setPrettyPrint(true).encodeResourceToString(result.toOperationOutcome());
|
||||||
ourLog.info(resultString);
|
ourLog.info(resultString);
|
||||||
|
|
||||||
assertEquals(2, ((OperationOutcome)result.toOperationOutcome()).getIssue().size());
|
assertEquals(2, ((OperationOutcome)result.toOperationOutcome()).getIssue().size());
|
||||||
assertThat(resultString, StringContains.containsString("cvc-datatype-valid.1.2.3"));
|
assertThat(resultString, StringContains.containsString("cvc-datatype-valid.1.2.3"));
|
||||||
|
|
||||||
|
try {
|
||||||
|
parser.parseResource(encoded);
|
||||||
|
fail();
|
||||||
|
} catch (DataFormatException e) {
|
||||||
|
assertEquals("DataFormatException at [[row,col {unknown-source}]: [2,4]]: Invalid attribute value \"2000-15-31\": Invalid date/time format: \"2000-15-31\"", e.getMessage());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -170,7 +170,10 @@ public class JsonParserDstu2Test {
|
|||||||
@Test
|
@Test
|
||||||
public void testParseEmptyValue() {
|
public void testParseEmptyValue() {
|
||||||
String input = "{\"resourceType\":\"QuestionnaireResponse\",\"id\":\"123\",\"authored\":\"\",\"group\":{\"linkId\":\"\"}}";
|
String input = "{\"resourceType\":\"QuestionnaireResponse\",\"id\":\"123\",\"authored\":\"\",\"group\":{\"linkId\":\"\"}}";
|
||||||
QuestionnaireResponse qr = ourCtx.newJsonParser().parseResource(QuestionnaireResponse.class, input);
|
IParser parser = ourCtx.newJsonParser();
|
||||||
|
|
||||||
|
parser.setParserErrorHandler(new LenientErrorHandler().setErrorOnInvalidValue(false));
|
||||||
|
QuestionnaireResponse qr = parser.parseResource(QuestionnaireResponse.class, input);
|
||||||
|
|
||||||
assertEquals("QuestionnaireResponse/123", qr.getIdElement().getValue());
|
assertEquals("QuestionnaireResponse/123", qr.getIdElement().getValue());
|
||||||
assertEquals(null, qr.getAuthored());
|
assertEquals(null, qr.getAuthored());
|
||||||
|
@ -2524,7 +2524,10 @@ public class XmlParserDstu2Test {
|
|||||||
"</Patient>";
|
"</Patient>";
|
||||||
//@formatter:on
|
//@formatter:on
|
||||||
|
|
||||||
ourCtx.newXmlParser().parseResource(resource);
|
|
||||||
|
IParser parser = ourCtx.newXmlParser();
|
||||||
|
parser.setParserErrorHandler(new StrictErrorHandler());
|
||||||
|
parser.parseResource(resource);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -40,10 +40,12 @@ import ca.uhn.fhir.model.dstu2.valueset.ContactPointSystemEnum;
|
|||||||
import ca.uhn.fhir.model.dstu2.valueset.NarrativeStatusEnum;
|
import ca.uhn.fhir.model.dstu2.valueset.NarrativeStatusEnum;
|
||||||
import ca.uhn.fhir.model.dstu2.valueset.UnitsOfTimeEnum;
|
import ca.uhn.fhir.model.dstu2.valueset.UnitsOfTimeEnum;
|
||||||
import ca.uhn.fhir.model.primitive.DateDt;
|
import ca.uhn.fhir.model.primitive.DateDt;
|
||||||
|
import ca.uhn.fhir.model.primitive.DateTimeDt;
|
||||||
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.DataFormatException;
|
import ca.uhn.fhir.parser.DataFormatException;
|
||||||
import ca.uhn.fhir.parser.IParser;
|
import ca.uhn.fhir.parser.IParser;
|
||||||
|
import ca.uhn.fhir.parser.StrictErrorHandler;
|
||||||
import ca.uhn.fhir.parser.XmlParserDstu2Test.TestPatientFor327;
|
import ca.uhn.fhir.parser.XmlParserDstu2Test.TestPatientFor327;
|
||||||
import ca.uhn.fhir.util.TestUtil;
|
import ca.uhn.fhir.util.TestUtil;
|
||||||
import ca.uhn.fhir.validation.schematron.SchematronBaseValidator;
|
import ca.uhn.fhir.validation.schematron.SchematronBaseValidator;
|
||||||
@ -71,26 +73,33 @@ public class ResourceValidatorDstu2Test {
|
|||||||
/**
|
/**
|
||||||
* See issue #50
|
* See issue #50
|
||||||
*/
|
*/
|
||||||
@Test(expected=DataFormatException.class)
|
@Test()
|
||||||
public void testOutOfBoundsDate() {
|
public void testOutOfBoundsDate() {
|
||||||
Patient p = new Patient();
|
Patient p = new Patient();
|
||||||
p.setBirthDate(new DateDt("2000-15-31"));
|
p.setBirthDate(new DateDt("2000-12-31"));
|
||||||
|
|
||||||
String encoded = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(p);
|
// Put in an invalid date
|
||||||
|
IParser parser = ourCtx.newXmlParser();
|
||||||
|
parser.setParserErrorHandler(new StrictErrorHandler());
|
||||||
|
|
||||||
|
String encoded = parser.setPrettyPrint(true).encodeResourceToString(p).replace("2000-12-31", "2000-15-31");
|
||||||
ourLog.info(encoded);
|
ourLog.info(encoded);
|
||||||
|
|
||||||
assertThat(encoded, StringContains.containsString("2000-15-31"));
|
assertThat(encoded, StringContains.containsString("2000-15-31"));
|
||||||
|
|
||||||
p = ourCtx.newXmlParser().parseResource(Patient.class, encoded);
|
ValidationResult result = ourCtx.newValidator().validateWithResult(encoded);
|
||||||
assertEquals("2000-15-31", p.getBirthDateElement().getValueAsString());
|
String resultString = parser.setPrettyPrint(true).encodeResourceToString(result.toOperationOutcome());
|
||||||
assertEquals("2001-03-31", new SimpleDateFormat("yyyy-MM-dd").format(p.getBirthDate()));
|
|
||||||
|
|
||||||
ValidationResult result = ourCtx.newValidator().validateWithResult(p);
|
|
||||||
String resultString = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(result.toOperationOutcome());
|
|
||||||
ourLog.info(resultString);
|
ourLog.info(resultString);
|
||||||
|
|
||||||
assertEquals(2, ((OperationOutcome) result.toOperationOutcome()).getIssue().size());
|
assertEquals(2, ((OperationOutcome)result.toOperationOutcome()).getIssue().size());
|
||||||
assertThat(resultString, StringContains.containsString("2000-15-31"));
|
assertThat(resultString, StringContains.containsString("cvc-pattern-valid"));
|
||||||
|
|
||||||
|
try {
|
||||||
|
parser.parseResource(encoded);
|
||||||
|
fail();
|
||||||
|
} catch (DataFormatException e) {
|
||||||
|
assertEquals("DataFormatException at [[row,col {unknown-source}]: [2,4]]: Invalid attribute value \"2000-15-31\": Invalid date/time format: \"2000-15-31\"", e.getMessage());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("deprecation")
|
@SuppressWarnings("deprecation")
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package org.hl7.fhir.dstu3.model;
|
package org.hl7.fhir.dstu3.model;
|
||||||
|
|
||||||
import static org.apache.commons.lang3.StringUtils.isBlank;
|
import static org.apache.commons.lang3.StringUtils.isBlank;
|
||||||
|
import static org.hamcrest.Matchers.emptyOrNullString;
|
||||||
|
|
||||||
import java.util.Calendar;
|
import java.util.Calendar;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
@ -334,7 +335,7 @@ public abstract class BaseDateTimeType extends PrimitiveType<Date> {
|
|||||||
myFractionalSeconds = "";
|
myFractionalSeconds = "";
|
||||||
}
|
}
|
||||||
|
|
||||||
setPrecision(precision);
|
myPrecision = precision;
|
||||||
return cal.getTime();
|
return cal.getTime();
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -372,8 +373,8 @@ public abstract class BaseDateTimeType extends PrimitiveType<Date> {
|
|||||||
if (isBlank(theValue)) {
|
if (isBlank(theValue)) {
|
||||||
throwBadDateFormat(theWholeValue);
|
throwBadDateFormat(theWholeValue);
|
||||||
} else if (theValue.charAt(0) == 'Z') {
|
} else if (theValue.charAt(0) == 'Z') {
|
||||||
clearTimeZone();
|
myTimeZone = null;
|
||||||
setTimeZoneZulu(true);
|
myTimeZoneZulu = true;
|
||||||
} else if (theValue.length() != 6) {
|
} else if (theValue.length() != 6) {
|
||||||
throwBadDateFormat(theWholeValue, "Timezone offset must be in the form \"Z\", \"-HH:mm\", or \"+HH:mm\"");
|
throwBadDateFormat(theWholeValue, "Timezone offset must be in the form \"Z\", \"-HH:mm\", or \"+HH:mm\"");
|
||||||
} else if (theValue.charAt(3) != ':' || !(theValue.charAt(0) == '+' || theValue.charAt(0) == '-')) {
|
} else if (theValue.charAt(3) != ':' || !(theValue.charAt(0) == '+' || theValue.charAt(0) == '-')) {
|
||||||
@ -381,8 +382,8 @@ public abstract class BaseDateTimeType extends PrimitiveType<Date> {
|
|||||||
} else {
|
} else {
|
||||||
parseInt(theWholeValue, theValue.substring(1, 3), 0, 23);
|
parseInt(theWholeValue, theValue.substring(1, 3), 0, 23);
|
||||||
parseInt(theWholeValue, theValue.substring(4, 6), 0, 59);
|
parseInt(theWholeValue, theValue.substring(4, 6), 0, 59);
|
||||||
clearTimeZone();
|
myTimeZoneZulu = false;
|
||||||
setTimeZone(TimeZone.getTimeZone("GMT" + theValue));
|
myTimeZone = TimeZone.getTimeZone("GMT" + theValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
@ -390,12 +391,14 @@ public abstract class BaseDateTimeType extends PrimitiveType<Date> {
|
|||||||
|
|
||||||
public BaseDateTimeType setTimeZone(TimeZone theTimeZone) {
|
public BaseDateTimeType setTimeZone(TimeZone theTimeZone) {
|
||||||
myTimeZone = theTimeZone;
|
myTimeZone = theTimeZone;
|
||||||
|
myTimeZoneZulu = false;
|
||||||
updateStringValue();
|
updateStringValue();
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public BaseDateTimeType setTimeZoneZulu(boolean theTimeZoneZulu) {
|
public BaseDateTimeType setTimeZoneZulu(boolean theTimeZoneZulu) {
|
||||||
myTimeZoneZulu = theTimeZoneZulu;
|
myTimeZoneZulu = theTimeZoneZulu;
|
||||||
|
myTimeZone = null;
|
||||||
updateStringValue();
|
updateStringValue();
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
@ -70,13 +70,13 @@ public abstract class PrimitiveType<T> extends Type implements IPrimitiveType<T>
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void fromStringValue(String theValue) {
|
public void fromStringValue(String theValue) {
|
||||||
|
myStringValue = theValue;
|
||||||
if (theValue == null) {
|
if (theValue == null) {
|
||||||
myCoercedValue = null;
|
myCoercedValue = null;
|
||||||
} else {
|
} else {
|
||||||
// NB this might be null
|
// NB this might be null
|
||||||
myCoercedValue = parse(theValue);
|
myCoercedValue = parse(theValue);
|
||||||
}
|
}
|
||||||
myStringValue = theValue;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public T getValue() {
|
public T getValue() {
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
package ca.uhn.fhir.parser;
|
package ca.uhn.fhir.parser;
|
||||||
|
|
||||||
|
import static org.junit.Assert.*;
|
||||||
|
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
import ca.uhn.fhir.parser.json.JsonLikeValue.ValueType;
|
import ca.uhn.fhir.parser.json.JsonLikeValue.ValueType;
|
||||||
@ -46,7 +48,14 @@ public class ErrorHandlerTest {
|
|||||||
new LenientErrorHandler().containedResourceWithNoId(null);
|
new LenientErrorHandler().containedResourceWithNoId(null);
|
||||||
new LenientErrorHandler().unknownReference(null, null);
|
new LenientErrorHandler().unknownReference(null, null);
|
||||||
new LenientErrorHandler().incorrectJsonType(null, null, ValueType.ARRAY, ValueType.SCALAR);
|
new LenientErrorHandler().incorrectJsonType(null, null, ValueType.ARRAY, ValueType.SCALAR);
|
||||||
new LenientErrorHandler().invalidValue(null, null, null);
|
new LenientErrorHandler().setErrorOnInvalidValue(false).invalidValue(null, "FOO", "");
|
||||||
|
new LenientErrorHandler().invalidValue(null, null, "");
|
||||||
|
try {
|
||||||
|
new LenientErrorHandler().invalidValue(null, "FOO", "");
|
||||||
|
fail();
|
||||||
|
} catch (DataFormatException e) {
|
||||||
|
// good, this one method defaults to causing an error
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test(expected = DataFormatException.class)
|
@Test(expected = DataFormatException.class)
|
||||||
|
@ -13,35 +13,78 @@ import static org.junit.Assert.assertSame;
|
|||||||
import static org.junit.Assert.assertThat;
|
import static org.junit.Assert.assertThat;
|
||||||
import static org.junit.Assert.assertTrue;
|
import static org.junit.Assert.assertTrue;
|
||||||
import static org.junit.Assert.fail;
|
import static org.junit.Assert.fail;
|
||||||
|
import static org.mockito.Matchers.eq;
|
||||||
|
import static org.mockito.Matchers.isNull;
|
||||||
import static org.mockito.Mockito.atLeastOnce;
|
import static org.mockito.Mockito.atLeastOnce;
|
||||||
import static org.mockito.Mockito.mock;
|
import static org.mockito.Mockito.mock;
|
||||||
import static org.mockito.Mockito.times;
|
import static org.mockito.Mockito.times;
|
||||||
import static org.mockito.Mockito.verify;
|
import static org.mockito.Mockito.verify;
|
||||||
|
|
||||||
import java.io.ByteArrayInputStream;
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.ObjectInputStream;
|
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.util.*;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
import org.apache.commons.io.IOUtils;
|
import org.apache.commons.io.IOUtils;
|
||||||
import org.hamcrest.Matchers;
|
import org.hamcrest.Matchers;
|
||||||
import org.hamcrest.core.StringContains;
|
import org.hamcrest.core.StringContains;
|
||||||
import org.hl7.fhir.dstu3.model.*;
|
|
||||||
import org.hl7.fhir.dstu3.model.Address.AddressUse;
|
import org.hl7.fhir.dstu3.model.Address.AddressUse;
|
||||||
import org.hl7.fhir.dstu3.model.Address.AddressUseEnumFactory;
|
import org.hl7.fhir.dstu3.model.Address.AddressUseEnumFactory;
|
||||||
|
import org.hl7.fhir.dstu3.model.Attachment;
|
||||||
|
import org.hl7.fhir.dstu3.model.AuditEvent;
|
||||||
|
import org.hl7.fhir.dstu3.model.Basic;
|
||||||
|
import org.hl7.fhir.dstu3.model.Binary;
|
||||||
|
import org.hl7.fhir.dstu3.model.Bundle;
|
||||||
import org.hl7.fhir.dstu3.model.Bundle.BundleEntryComponent;
|
import org.hl7.fhir.dstu3.model.Bundle.BundleEntryComponent;
|
||||||
import org.hl7.fhir.dstu3.model.Bundle.BundleType;
|
import org.hl7.fhir.dstu3.model.Bundle.BundleType;
|
||||||
|
import org.hl7.fhir.dstu3.model.Claim;
|
||||||
|
import org.hl7.fhir.dstu3.model.Coding;
|
||||||
|
import org.hl7.fhir.dstu3.model.Communication;
|
||||||
|
import org.hl7.fhir.dstu3.model.Condition;
|
||||||
import org.hl7.fhir.dstu3.model.Condition.ConditionVerificationStatus;
|
import org.hl7.fhir.dstu3.model.Condition.ConditionVerificationStatus;
|
||||||
|
import org.hl7.fhir.dstu3.model.Conformance;
|
||||||
import org.hl7.fhir.dstu3.model.Conformance.UnknownContentCode;
|
import org.hl7.fhir.dstu3.model.Conformance.UnknownContentCode;
|
||||||
|
import org.hl7.fhir.dstu3.model.Coverage;
|
||||||
|
import org.hl7.fhir.dstu3.model.DateTimeType;
|
||||||
|
import org.hl7.fhir.dstu3.model.DateType;
|
||||||
|
import org.hl7.fhir.dstu3.model.DecimalType;
|
||||||
|
import org.hl7.fhir.dstu3.model.DiagnosticReport;
|
||||||
|
import org.hl7.fhir.dstu3.model.EnumFactory;
|
||||||
import org.hl7.fhir.dstu3.model.Enumeration;
|
import org.hl7.fhir.dstu3.model.Enumeration;
|
||||||
import org.hl7.fhir.dstu3.model.Enumerations.AdministrativeGender;
|
import org.hl7.fhir.dstu3.model.Enumerations.AdministrativeGender;
|
||||||
|
import org.hl7.fhir.dstu3.model.ExplanationOfBenefit;
|
||||||
|
import org.hl7.fhir.dstu3.model.Extension;
|
||||||
|
import org.hl7.fhir.dstu3.model.HumanName;
|
||||||
|
import org.hl7.fhir.dstu3.model.IdType;
|
||||||
import org.hl7.fhir.dstu3.model.Identifier.IdentifierUse;
|
import org.hl7.fhir.dstu3.model.Identifier.IdentifierUse;
|
||||||
|
import org.hl7.fhir.dstu3.model.Linkage;
|
||||||
|
import org.hl7.fhir.dstu3.model.Medication;
|
||||||
|
import org.hl7.fhir.dstu3.model.MedicationRequest;
|
||||||
|
import org.hl7.fhir.dstu3.model.Observation;
|
||||||
import org.hl7.fhir.dstu3.model.Observation.ObservationStatus;
|
import org.hl7.fhir.dstu3.model.Observation.ObservationStatus;
|
||||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
import org.hl7.fhir.dstu3.model.Parameters;
|
||||||
|
import org.hl7.fhir.dstu3.model.Patient;
|
||||||
|
import org.hl7.fhir.dstu3.model.PrimitiveType;
|
||||||
|
import org.hl7.fhir.dstu3.model.Quantity;
|
||||||
|
import org.hl7.fhir.dstu3.model.QuestionnaireResponse;
|
||||||
|
import org.hl7.fhir.dstu3.model.Reference;
|
||||||
|
import org.hl7.fhir.dstu3.model.RelatedPerson;
|
||||||
|
import org.hl7.fhir.dstu3.model.SampledData;
|
||||||
|
import org.hl7.fhir.dstu3.model.SimpleQuantity;
|
||||||
|
import org.hl7.fhir.dstu3.model.StringType;
|
||||||
|
import org.hl7.fhir.dstu3.model.UriType;
|
||||||
|
import org.hl7.fhir.dstu3.model.ValueSet;
|
||||||
import org.hl7.fhir.utilities.xhtml.XhtmlNode;
|
import org.hl7.fhir.utilities.xhtml.XhtmlNode;
|
||||||
import org.junit.*;
|
import org.junit.After;
|
||||||
|
import org.junit.AfterClass;
|
||||||
|
import org.junit.Assert;
|
||||||
|
import org.junit.Ignore;
|
||||||
|
import org.junit.Test;
|
||||||
import org.mockito.ArgumentCaptor;
|
import org.mockito.ArgumentCaptor;
|
||||||
import org.mockito.Mockito;
|
import org.mockito.Mockito;
|
||||||
|
|
||||||
@ -49,7 +92,6 @@ import com.google.common.collect.Sets;
|
|||||||
|
|
||||||
import ca.uhn.fhir.context.FhirContext;
|
import ca.uhn.fhir.context.FhirContext;
|
||||||
import ca.uhn.fhir.narrative.DefaultThymeleafNarrativeGenerator;
|
import ca.uhn.fhir.narrative.DefaultThymeleafNarrativeGenerator;
|
||||||
import ca.uhn.fhir.parser.DataFormatException;
|
|
||||||
import ca.uhn.fhir.parser.IParserErrorHandler.IParseLocation;
|
import ca.uhn.fhir.parser.IParserErrorHandler.IParseLocation;
|
||||||
import ca.uhn.fhir.parser.PatientWithExtendedContactDstu3.CustomContactComponent;
|
import ca.uhn.fhir.parser.PatientWithExtendedContactDstu3.CustomContactComponent;
|
||||||
import ca.uhn.fhir.parser.XmlParserDstu3Test.TestPatientFor327;
|
import ca.uhn.fhir.parser.XmlParserDstu3Test.TestPatientFor327;
|
||||||
@ -93,7 +135,7 @@ public class JsonParserDstu3Test {
|
|||||||
IParser p = ourCtx.newJsonParser().setPrettyPrint(true);
|
IParser p = ourCtx.newJsonParser().setPrettyPrint(true);
|
||||||
String encoded = p.encodeResourceToString(resource);
|
String encoded = p.encodeResourceToString(resource);
|
||||||
ourLog.info(encoded);
|
ourLog.info(encoded);
|
||||||
|
|
||||||
assertEquals(3, countMatches(encoded, "resourceType"));
|
assertEquals(3, countMatches(encoded, "resourceType"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -122,15 +164,18 @@ public class JsonParserDstu3Test {
|
|||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
public void testParseEmptyValue() {
|
public void testParseEmptyValue() {
|
||||||
String input = "{\"resourceType\":\"QuestionnaireResponse\",\"id\":\"123\",\"authored\":\"\",\"item\":[{\"item\":[{\"linkId\":\"\"}]}]}";
|
String input = "{\"resourceType\":\"QuestionnaireResponse\",\"id\":\"123\",\"authored\":\"\",\"group\":{\"linkId\":\"\"}}";
|
||||||
QuestionnaireResponse qr = ourCtx.newJsonParser().parseResource(QuestionnaireResponse.class, input);
|
IParser parser = ourCtx.newJsonParser();
|
||||||
|
|
||||||
|
parser.setParserErrorHandler(new LenientErrorHandler().setErrorOnInvalidValue(false));
|
||||||
|
QuestionnaireResponse qr = parser.parseResource(QuestionnaireResponse.class, input);
|
||||||
|
|
||||||
assertEquals("QuestionnaireResponse/123", qr.getIdElement().getValue());
|
assertEquals("QuestionnaireResponse/123", qr.getIdElement().getValue());
|
||||||
assertEquals(null, qr.getAuthored());
|
assertEquals(null, qr.getAuthored());
|
||||||
assertEquals(null, qr.getAuthoredElement().getValue());
|
assertEquals(null, qr.getAuthoredElement().getValue());
|
||||||
assertEquals(null, qr.getAuthoredElement().getValueAsString());
|
assertEquals(null, qr.getAuthoredElement().getValueAsString());
|
||||||
assertEquals(null, qr.getItemFirstRep().getItemFirstRep().getLinkId());
|
assertEquals(null, qr.getItemFirstRep().getLinkId());
|
||||||
assertEquals(null, qr.getItemFirstRep().getItemFirstRep().getLinkIdElement().getValue());
|
assertEquals(null, qr.getItemFirstRep().getLinkIdElement().getValue());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1194,17 +1239,77 @@ public class JsonParserDstu3Test {
|
|||||||
assertEquals("{\"resourceType\":\"Observation\",\"valueQuantity\":{\"value\":0.0000000000000001}}", str);
|
assertEquals("{\"resourceType\":\"Observation\",\"valueQuantity\":{\"value\":0.0000000000000001}}", str);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* #516
|
* #516
|
||||||
*/
|
*/
|
||||||
@Test(expected=DataFormatException.class)
|
@Test(expected = DataFormatException.class)
|
||||||
public void testInvalidEnumValue() {
|
public void testInvalidEnumValue() {
|
||||||
String res = "{ \"resourceType\": \"ValueSet\", \"url\": \"http://sample/ValueSet/education-levels\", \"version\": \"1\", \"name\": \"Education Levels\", \"status\": \"draft\", \"compose\": { \"include\": [ { \"filter\": [ { \"property\": \"n\", \"op\": \"n\", \"value\": \"365460000\" } ], \"system\": \"http://snomed.info/sct\" } ], \"exclude\": [ { \"concept\": [ { \"code\": \"224298008\" }, { \"code\": \"365460000\" }, { \"code\": \"473462005\" }, { \"code\": \"424587006\" } ], \"system\": \"http://snomed.info/sct\" } ] }, \"description\": \"A selection of Education Levels\", \"text\": { \"status\": \"generated\", \"div\": \"<div xmlns=\\\"http://www.w3.org/1999/xhtml\\\"><h2>Education Levels</h2><tt>http://csiro.au/ValueSet/education-levels</tt><p>A selection of Education Levels</p></div>\" }, \"experimental\": true, \"date\": \"2016-07-26\" }";
|
String res = "{ \"resourceType\": \"ValueSet\", \"url\": \"http://sample/ValueSet/education-levels\", \"version\": \"1\", \"name\": \"Education Levels\", \"status\": \"draft\", \"compose\": { \"include\": [ { \"filter\": [ { \"property\": \"n\", \"op\": \"n\", \"value\": \"365460000\" } ], \"system\": \"http://snomed.info/sct\" } ], \"exclude\": [ { \"concept\": [ { \"code\": \"224298008\" }, { \"code\": \"365460000\" }, { \"code\": \"473462005\" }, { \"code\": \"424587006\" } ], \"system\": \"http://snomed.info/sct\" } ] }, \"description\": \"A selection of Education Levels\", \"text\": { \"status\": \"generated\", \"div\": \"<div xmlns=\\\"http://www.w3.org/1999/xhtml\\\"><h2>Education Levels</h2><tt>http://csiro.au/ValueSet/education-levels</tt><p>A selection of Education Levels</p></div>\" }, \"experimental\": true, \"date\": \"2016-07-26\" }";
|
||||||
IParser parser = ourCtx.newJsonParser();
|
IParser parser = ourCtx.newJsonParser();
|
||||||
parser.setParserErrorHandler(new StrictErrorHandler());
|
parser.setParserErrorHandler(new StrictErrorHandler());
|
||||||
ValueSet parsed = parser.parseResource(ValueSet.class, res);
|
ValueSet parsed = parser.parseResource(ValueSet.class, res);
|
||||||
fail("DataFormat Invalid attribute exception should be thrown");
|
fail("DataFormat Invalid attribute exception should be thrown");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testInvalidEnumValueBlank() {
|
||||||
|
IParserErrorHandler errorHandler = mock(IParserErrorHandler.class);
|
||||||
|
|
||||||
|
String res = "{ \"resourceType\": \"Patient\", \"gender\": \"\" }";
|
||||||
|
IParser parser = ourCtx.newJsonParser();
|
||||||
|
parser.setParserErrorHandler(errorHandler);
|
||||||
|
Patient parsed = parser.parseResource(Patient.class, res);
|
||||||
|
|
||||||
|
assertEquals(null, parsed.getGenderElement().getValue());
|
||||||
|
assertEquals(null, parsed.getGenderElement().getValueAsString());
|
||||||
|
|
||||||
|
ArgumentCaptor<String> msgCaptor = ArgumentCaptor.forClass(String.class);
|
||||||
|
verify(errorHandler, times(1)).invalidValue(isNull(IParseLocation.class), eq(""), msgCaptor.capture());
|
||||||
|
assertEquals("Attribute values must not be empty (\"\")", msgCaptor.getValue());
|
||||||
|
|
||||||
|
String encoded = ourCtx.newJsonParser().encodeResourceToString(parsed);
|
||||||
|
assertEquals("{\"resourceType\":\"Patient\"}", encoded);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testInvalidEnumValueInvalid() {
|
||||||
|
IParserErrorHandler errorHandler = mock(IParserErrorHandler.class);
|
||||||
|
|
||||||
|
String res = "{ \"resourceType\": \"Patient\", \"gender\": \"foo\" }";
|
||||||
|
IParser parser = ourCtx.newJsonParser();
|
||||||
|
parser.setParserErrorHandler(errorHandler);
|
||||||
|
Patient parsed = parser.parseResource(Patient.class, res);
|
||||||
|
|
||||||
|
assertEquals(null, parsed.getGenderElement().getValue());
|
||||||
|
assertEquals("foo", parsed.getGenderElement().getValueAsString());
|
||||||
|
|
||||||
|
ArgumentCaptor<String> msgCaptor = ArgumentCaptor.forClass(String.class);
|
||||||
|
verify(errorHandler, times(1)).invalidValue(isNull(IParseLocation.class), eq("foo"), msgCaptor.capture());
|
||||||
|
assertEquals("Unknown AdministrativeGender code 'foo'", msgCaptor.getValue());
|
||||||
|
|
||||||
|
String encoded = ourCtx.newJsonParser().encodeResourceToString(parsed);
|
||||||
|
assertEquals("{\"resourceType\":\"Patient\",\"gender\":\"foo\"}", encoded);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testInvalidDateTimeValueInvalid() throws Exception {
|
||||||
|
IParserErrorHandler errorHandler = mock(IParserErrorHandler.class);
|
||||||
|
|
||||||
|
String res = "{ \"resourceType\": \"Observation\", \"valueDateTime\": \"foo\" }";
|
||||||
|
IParser parser = ourCtx.newJsonParser();
|
||||||
|
parser.setParserErrorHandler(errorHandler);
|
||||||
|
Observation parsed = parser.parseResource(Observation.class, res);
|
||||||
|
|
||||||
|
assertEquals(null, parsed.getValueDateTimeType().getValue());
|
||||||
|
assertEquals("foo", parsed.getValueDateTimeType().getValueAsString());
|
||||||
|
|
||||||
|
ArgumentCaptor<String> msgCaptor = ArgumentCaptor.forClass(String.class);
|
||||||
|
verify(errorHandler, times(1)).invalidValue(isNull(IParseLocation.class), eq("foo"), msgCaptor.capture());
|
||||||
|
assertEquals("Invalid date/time format: \"foo\"", msgCaptor.getValue());
|
||||||
|
|
||||||
|
String encoded = ourCtx.newJsonParser().encodeResourceToString(parsed);
|
||||||
|
assertEquals("{\"resourceType\":\"Observation\",\"valueDateTime\":\"foo\"}", encoded);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* #65
|
* #65
|
||||||
|
@ -2855,7 +2855,7 @@ public class XmlParserDstu3Test {
|
|||||||
/**
|
/**
|
||||||
* See #366
|
* See #366
|
||||||
*/
|
*/
|
||||||
@Test(expected = DataFormatException.class)
|
@Test()
|
||||||
public void testParseInvalidBoolean() {
|
public void testParseInvalidBoolean() {
|
||||||
//@formatter:off
|
//@formatter:off
|
||||||
String resource = "<Patient xmlns=\"http://hl7.org/fhir\">\n" +
|
String resource = "<Patient xmlns=\"http://hl7.org/fhir\">\n" +
|
||||||
@ -2863,7 +2863,19 @@ public class XmlParserDstu3Test {
|
|||||||
"</Patient>";
|
"</Patient>";
|
||||||
//@formatter:on
|
//@formatter:on
|
||||||
|
|
||||||
ourCtx.newXmlParser().parseResource(resource);
|
IParser p = ourCtx.newXmlParser();
|
||||||
|
|
||||||
|
try {
|
||||||
|
p.parseResource(resource);
|
||||||
|
fail();
|
||||||
|
} catch (DataFormatException e) {
|
||||||
|
assertEquals("DataFormatException at [[row,col {unknown-source}]: [2,4]]: Invalid attribute value \"1\": Invalid boolean string: '1'", e.getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
LenientErrorHandler errorHandler = new LenientErrorHandler();
|
||||||
|
assertEquals(true, errorHandler.isErrorOnInvalidValue());
|
||||||
|
errorHandler.setErrorOnInvalidValue(false);
|
||||||
|
p.setParserErrorHandler(errorHandler);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -3,8 +3,10 @@ package org.hl7.fhir.dstu3.hapi.validation;
|
|||||||
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.assertThat;
|
import static org.junit.Assert.assertThat;
|
||||||
import static org.junit.Assert.assertTrue;
|
import static org.junit.Assert.assertTrue;
|
||||||
|
import static org.junit.Assert.fail;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
@ -12,14 +14,24 @@ import java.util.Date;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import org.apache.commons.io.IOUtils;
|
import org.apache.commons.io.IOUtils;
|
||||||
import org.hl7.fhir.dstu3.model.*;
|
import org.hamcrest.core.StringContains;
|
||||||
|
import org.hl7.fhir.dstu3.model.CodeableConcept;
|
||||||
|
import org.hl7.fhir.dstu3.model.Coding;
|
||||||
|
import org.hl7.fhir.dstu3.model.Condition;
|
||||||
import org.hl7.fhir.dstu3.model.Condition.ConditionVerificationStatus;
|
import org.hl7.fhir.dstu3.model.Condition.ConditionVerificationStatus;
|
||||||
|
import org.hl7.fhir.dstu3.model.DateType;
|
||||||
import org.hl7.fhir.dstu3.model.Narrative.NarrativeStatus;
|
import org.hl7.fhir.dstu3.model.Narrative.NarrativeStatus;
|
||||||
|
import org.hl7.fhir.dstu3.model.OperationOutcome;
|
||||||
|
import org.hl7.fhir.dstu3.model.Patient;
|
||||||
|
import org.hl7.fhir.dstu3.model.Reference;
|
||||||
|
import org.hl7.fhir.dstu3.model.StringType;
|
||||||
import org.junit.AfterClass;
|
import org.junit.AfterClass;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
import ca.uhn.fhir.context.FhirContext;
|
import ca.uhn.fhir.context.FhirContext;
|
||||||
|
import ca.uhn.fhir.parser.DataFormatException;
|
||||||
import ca.uhn.fhir.parser.IParser;
|
import ca.uhn.fhir.parser.IParser;
|
||||||
|
import ca.uhn.fhir.parser.StrictErrorHandler;
|
||||||
import ca.uhn.fhir.parser.XmlParserDstu3Test;
|
import ca.uhn.fhir.parser.XmlParserDstu3Test;
|
||||||
import ca.uhn.fhir.util.TestUtil;
|
import ca.uhn.fhir.util.TestUtil;
|
||||||
import ca.uhn.fhir.validation.FhirValidator;
|
import ca.uhn.fhir.validation.FhirValidator;
|
||||||
@ -37,6 +49,39 @@ public class ResourceValidatorDstu3Test {
|
|||||||
TestUtil.clearAllStaticFieldsForUnitTest();
|
TestUtil.clearAllStaticFieldsForUnitTest();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* See issue #50
|
||||||
|
*/
|
||||||
|
@Test()
|
||||||
|
public void testOutOfBoundsDate() {
|
||||||
|
Patient p = new Patient();
|
||||||
|
p.setBirthDateElement(new DateType("2000-12-31"));
|
||||||
|
|
||||||
|
// Put in an invalid date
|
||||||
|
IParser parser = ourCtx.newXmlParser();
|
||||||
|
parser.setParserErrorHandler(new StrictErrorHandler());
|
||||||
|
|
||||||
|
String encoded = parser.setPrettyPrint(true).encodeResourceToString(p).replace("2000-12-31", "2000-15-31");
|
||||||
|
ourLog.info(encoded);
|
||||||
|
|
||||||
|
assertThat(encoded, StringContains.containsString("2000-15-31"));
|
||||||
|
|
||||||
|
ValidationResult result = ourCtx.newValidator().validateWithResult(encoded);
|
||||||
|
String resultString = parser.setPrettyPrint(true).encodeResourceToString(result.toOperationOutcome());
|
||||||
|
ourLog.info(resultString);
|
||||||
|
|
||||||
|
assertEquals(2, ((OperationOutcome)result.toOperationOutcome()).getIssue().size());
|
||||||
|
assertThat(resultString, StringContains.containsString("cvc-pattern-valid"));
|
||||||
|
|
||||||
|
try {
|
||||||
|
parser.parseResource(encoded);
|
||||||
|
fail();
|
||||||
|
} catch (DataFormatException e) {
|
||||||
|
assertEquals("DataFormatException at [[row,col {unknown-source}]: [2,4]]: Invalid attribute value \"2000-15-31\": Invalid date/time format: \"2000-15-31\"", e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Make sure that the elements that appear in all resources (meta, language, extension, etc) all appear in the correct order
|
* Make sure that the elements that appear in all resources (meta, language, extension, etc) all appear in the correct order
|
||||||
*/
|
*/
|
||||||
|
@ -99,6 +99,21 @@
|
|||||||
not by throwing an exception. Thanks to
|
not by throwing an exception. Thanks to
|
||||||
Michael Lawley for the pull request!
|
Michael Lawley for the pull request!
|
||||||
</action>
|
</action>
|
||||||
|
<action type="add" issue="516">
|
||||||
|
When parsing DSTU3 resources with enumerated
|
||||||
|
types that contain invalid values, the parser will now
|
||||||
|
invoke the parserErrorHandler. For example, when parsing
|
||||||
|
<![CDATA[
|
||||||
|
<code>{"resourceType":"Patient", "gender":"foo"}</code>
|
||||||
|
]]>
|
||||||
|
the previous behaviour was to throw an InvalidArgumentException.
|
||||||
|
Now, the parserErrorHandler is invoked. In addition, thw
|
||||||
|
LenientErrorHandler has been modified so that this one case
|
||||||
|
will result in a DataFormatException. This has the effect
|
||||||
|
that servers which receive an invalid enum velue will return
|
||||||
|
an HTTP 400 instead of an HTTP 500. Thanks to Jim
|
||||||
|
Steel for reporting!
|
||||||
|
</action>
|
||||||
</release>
|
</release>
|
||||||
<release version="2.1" date="2016-11-11">
|
<release version="2.1" date="2016-11-11">
|
||||||
<action type="add">
|
<action type="add">
|
||||||
|
@ -14,12 +14,6 @@
|
|||||||
sections below.
|
sections below.
|
||||||
</p>
|
</p>
|
||||||
<ul>
|
<ul>
|
||||||
<li>
|
|
||||||
<b>Resource Validation</b>
|
|
||||||
is validation of the raw or parsed resource against
|
|
||||||
the official FHIR validation rules (e.g. Schema/Schematron/Profile/StructureDefinition/ValueSet)
|
|
||||||
as well as against custom profiles which have been developed.
|
|
||||||
</li>
|
|
||||||
<li>
|
<li>
|
||||||
<b>Parser Validation</b>
|
<b>Parser Validation</b>
|
||||||
is validation at runtime during the parsing
|
is validation at runtime during the parsing
|
||||||
@ -31,10 +25,77 @@
|
|||||||
that no data is being lost during parsing, but is less comprehensive than resource validation
|
that no data is being lost during parsing, but is less comprehensive than resource validation
|
||||||
against raw text data.
|
against raw text data.
|
||||||
</li>
|
</li>
|
||||||
|
<li>
|
||||||
|
<b>Resource Validation</b>
|
||||||
|
is validation of the raw or parsed resource against
|
||||||
|
the official FHIR validation rules (e.g. Schema/Schematron/Profile/StructureDefinition/ValueSet)
|
||||||
|
as well as against custom profiles which have been developed.
|
||||||
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
|
<!-- Parser Validation -->
|
||||||
|
<section name="Parser Validation">
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Parser validation is controlled by calling
|
||||||
|
<code>setParserErrorHandler(IParserErrorHandler)</code>
|
||||||
|
on
|
||||||
|
either the FhirContext or on individual parser instances. This method
|
||||||
|
takes an
|
||||||
|
<code>IParserErrorHandler</code>
|
||||||
|
, which is a callback that
|
||||||
|
will be invoked any time a parse issue is detected.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
There are two implementations of
|
||||||
|
<code>IParserErrorHandler</code>
|
||||||
|
worth
|
||||||
|
mentioning. You can also supply your own implementation if you want.
|
||||||
|
</p>
|
||||||
|
<ul>
|
||||||
|
<li>
|
||||||
|
<a href="./apidocs/ca/uhn/fhir/parser/LenientErrorHandler.html">LenientErrorHandler</a>
|
||||||
|
logs any errors but does not abort parsing. By default this handler is used, and it
|
||||||
|
logs errors at "warning" level. It can also be configured to silently
|
||||||
|
ignore issues.
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<a href="./apidocs/ca/uhn/fhir/parser/StrictErrorHandler.html">StrictErrorHandler</a>
|
||||||
|
throws a
|
||||||
|
<code>DataFormatException</code>
|
||||||
|
if any errors are detected.
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
The following example shows how to configure a parser to use strict validation.
|
||||||
|
</p>
|
||||||
|
<macro name="snippet">
|
||||||
|
<param name="id" value="parserValidation" />
|
||||||
|
<param name="file" value="examples/src/main/java/example/ValidatorExamples.java" />
|
||||||
|
</macro>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
You can also configure the error handler at the FhirContext level, which is useful
|
||||||
|
for clients.
|
||||||
|
</p>
|
||||||
|
<macro name="snippet">
|
||||||
|
<param name="id" value="clientValidation" />
|
||||||
|
<param name="file" value="examples/src/main/java/example/ValidatorExamples.java" />
|
||||||
|
</macro>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
FhirContext level validators can also be useful on servers.
|
||||||
|
</p>
|
||||||
|
<macro name="snippet">
|
||||||
|
<param name="id" value="serverValidation" />
|
||||||
|
<param name="file" value="examples/src/main/java/example/ValidatorExamples.java" />
|
||||||
|
</macro>
|
||||||
|
|
||||||
|
</section>
|
||||||
|
|
||||||
<!-- RESOURCE VALIDATION -->
|
<!-- RESOURCE VALIDATION -->
|
||||||
|
|
||||||
<section name="Resource Validation">
|
<section name="Resource Validation">
|
||||||
@ -223,66 +284,6 @@
|
|||||||
|
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<section name="Parser Validation">
|
|
||||||
|
|
||||||
<p>
|
|
||||||
Parser validation is controlled by calling
|
|
||||||
<code>setParserErrorHandler(IParserErrorHandler)</code>
|
|
||||||
on
|
|
||||||
either the FhirContext or on individual parser instances. This method
|
|
||||||
takes an
|
|
||||||
<code>IParserErrorHandler</code>
|
|
||||||
, which is a callback that
|
|
||||||
will be invoked any time a parse issue is detected.
|
|
||||||
</p>
|
|
||||||
<p>
|
|
||||||
There are two implementations of
|
|
||||||
<code>IParserErrorHandler</code>
|
|
||||||
worth
|
|
||||||
mentioning. You can also supply your own implementation if you want.
|
|
||||||
</p>
|
|
||||||
<ul>
|
|
||||||
<li>
|
|
||||||
<a href="./apidocs/ca/uhn/fhir/parser/LenientErrorHandler.html">LenientErrorHandler</a>
|
|
||||||
logs any errors but does not abort parsing. By default this handler is used, and it
|
|
||||||
logs errors at "warning" level. It can also be configured to silently
|
|
||||||
ignore issues.
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<a href="./apidocs/ca/uhn/fhir/parser/StrictErrorHandler.html">StrictErrorHandler</a>
|
|
||||||
throws a
|
|
||||||
<code>DataFormatException</code>
|
|
||||||
if any errors are detected.
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
The following example shows how to configure a parser to use strict validation.
|
|
||||||
</p>
|
|
||||||
<macro name="snippet">
|
|
||||||
<param name="id" value="parserValidation" />
|
|
||||||
<param name="file" value="examples/src/main/java/example/ValidatorExamples.java" />
|
|
||||||
</macro>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
You can also configure the error handler at the FhirContext level, which is useful
|
|
||||||
for clients.
|
|
||||||
</p>
|
|
||||||
<macro name="snippet">
|
|
||||||
<param name="id" value="clientValidation" />
|
|
||||||
<param name="file" value="examples/src/main/java/example/ValidatorExamples.java" />
|
|
||||||
</macro>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
FhirContext level validators can also be useful on servers.
|
|
||||||
</p>
|
|
||||||
<macro name="snippet">
|
|
||||||
<param name="id" value="serverValidation" />
|
|
||||||
<param name="file" value="examples/src/main/java/example/ValidatorExamples.java" />
|
|
||||||
</macro>
|
|
||||||
|
|
||||||
</section>
|
|
||||||
|
|
||||||
</body>
|
</body>
|
||||||
|
|
||||||
</document>
|
</document>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user