Merge pull request #34 from jjathman/remove-validation-exception
Fixes #32 - removes new validation API that doesn't use exceptions
This commit is contained in:
commit
d140e0b829
|
@ -20,18 +20,15 @@ package ca.uhn.fhir.validation;
|
||||||
* #L%
|
* #L%
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Iterator;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import org.apache.commons.lang3.Validate;
|
|
||||||
|
|
||||||
import com.phloc.schematron.ISchematronResource;
|
|
||||||
|
|
||||||
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.model.dstu.resource.OperationOutcome;
|
import ca.uhn.fhir.model.dstu.resource.OperationOutcome;
|
||||||
|
import org.apache.commons.lang3.Validate;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Resource validator, which checks resources for compliance against various validation schemes (schemas, schematrons, etc.)
|
* Resource validator, which checks resources for compliance against various validation schemes (schemas, schematrons, etc.)
|
||||||
|
@ -133,25 +130,18 @@ public class FhirValidator {
|
||||||
/**
|
/**
|
||||||
* Validates a bundle instance, throwing a {@link ValidationFailureException} if the validation fails. This validation includes validation of all resources in the bundle.
|
* Validates a bundle instance, throwing a {@link ValidationFailureException} if the validation fails. This validation includes validation of all resources in the bundle.
|
||||||
*
|
*
|
||||||
* @param theResource
|
* @param theBundle
|
||||||
* The resource to validate
|
* The resource to validate
|
||||||
* @throws ValidationFailureException
|
* @throws ValidationFailureException
|
||||||
* If the validation fails
|
* If the validation fails
|
||||||
|
* @deprecated use {@link #validateWithResult(ca.uhn.fhir.model.api.Bundle)} instead
|
||||||
*/
|
*/
|
||||||
|
@Deprecated
|
||||||
public void validate(Bundle theBundle) {
|
public void validate(Bundle theBundle) {
|
||||||
Validate.notNull(theBundle, "theBundle must not be null");
|
ValidationResult validationResult = validateWithResult(theBundle);
|
||||||
|
if (!validationResult.isSuccessful()) {
|
||||||
ValidationContext<Bundle> ctx = ValidationContext.forBundle(myContext, theBundle);
|
throw new ValidationFailureException(validationResult.getOperationOutcome());
|
||||||
|
}
|
||||||
for (IValidator next : myValidators) {
|
|
||||||
next.validateBundle(ctx);
|
|
||||||
}
|
|
||||||
|
|
||||||
OperationOutcome oo = ctx.getOperationOutcome();
|
|
||||||
if (oo != null && oo.getIssue().size() > 0) {
|
|
||||||
throw new ValidationFailureException(oo);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -161,21 +151,54 @@ public class FhirValidator {
|
||||||
* The resource to validate
|
* The resource to validate
|
||||||
* @throws ValidationFailureException
|
* @throws ValidationFailureException
|
||||||
* If the validation fails
|
* If the validation fails
|
||||||
|
* @deprecated use {@link #validateWithResult(ca.uhn.fhir.model.api.IResource)} instead
|
||||||
*/
|
*/
|
||||||
|
@Deprecated
|
||||||
public void validate(IResource theResource) throws ValidationFailureException {
|
public void validate(IResource theResource) throws ValidationFailureException {
|
||||||
Validate.notNull(theResource, "theResource must not be null");
|
ValidationResult validationResult = validateWithResult(theResource);
|
||||||
|
if (!validationResult.isSuccessful()) {
|
||||||
|
throw new ValidationFailureException(validationResult.getOperationOutcome());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
ValidationContext<IResource> ctx = ValidationContext.forResource(myContext, theResource);
|
/**
|
||||||
|
* Validates a bundle instance returning a {@link ca.uhn.fhir.validation.ValidationResult} which contains the results.
|
||||||
|
* This validation includes validation of all resources in the bundle.
|
||||||
|
*
|
||||||
|
* @param theBundle the bundle to validate
|
||||||
|
* @return the results of validation
|
||||||
|
* @since 0.7
|
||||||
|
*/
|
||||||
|
public ValidationResult validateWithResult(Bundle theBundle) {
|
||||||
|
Validate.notNull(theBundle, "theBundle must not be null");
|
||||||
|
|
||||||
for (IValidator next : myValidators) {
|
ValidationContext<Bundle> ctx = ValidationContext.forBundle(myContext, theBundle);
|
||||||
next.validateResource(ctx);
|
|
||||||
}
|
|
||||||
|
|
||||||
OperationOutcome oo = ctx.getOperationOutcome();
|
for (IValidator next : myValidators) {
|
||||||
if (oo != null && oo.getIssue().size() > 0) {
|
next.validateBundle(ctx);
|
||||||
throw new ValidationFailureException(oo);
|
}
|
||||||
}
|
|
||||||
|
|
||||||
}
|
OperationOutcome oo = ctx.getOperationOutcome();
|
||||||
|
return ValidationResult.valueOf(oo);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Validates a resource instance returning a {@link ca.uhn.fhir.validation.ValidationResult} which contains the results.
|
||||||
|
*
|
||||||
|
* @param theResource the resource to validate
|
||||||
|
* @return the results of validation
|
||||||
|
* @since 0.7
|
||||||
|
*/
|
||||||
|
public ValidationResult validateWithResult(IResource theResource) {
|
||||||
|
Validate.notNull(theResource, "theResource must not be null");
|
||||||
|
|
||||||
|
ValidationContext<IResource> ctx = ValidationContext.forResource(myContext, theResource);
|
||||||
|
|
||||||
|
for (IValidator next : myValidators) {
|
||||||
|
next.validateResource(ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
OperationOutcome oo = ctx.getOperationOutcome();
|
||||||
|
return ValidationResult.valueOf(oo);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,72 @@
|
||||||
|
package ca.uhn.fhir.validation;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* #%L
|
||||||
|
* HAPI FHIR - Core Library
|
||||||
|
* %%
|
||||||
|
* Copyright (C) 2014 University Health Network
|
||||||
|
* %%
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
* #L%
|
||||||
|
*/
|
||||||
|
|
||||||
|
import ca.uhn.fhir.model.dstu.resource.OperationOutcome;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Encapsulates the results of validation
|
||||||
|
*
|
||||||
|
* @see ca.uhn.fhir.validation.FhirValidator
|
||||||
|
* @since 0.7
|
||||||
|
*/
|
||||||
|
public class ValidationResult {
|
||||||
|
private OperationOutcome myOperationOutcome;
|
||||||
|
|
||||||
|
private ValidationResult(OperationOutcome myOperationOutcome) {
|
||||||
|
this.myOperationOutcome = myOperationOutcome;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ValidationResult valueOf(OperationOutcome myOperationOutcome) {
|
||||||
|
return new ValidationResult(myOperationOutcome);
|
||||||
|
}
|
||||||
|
|
||||||
|
public OperationOutcome getOperationOutcome() {
|
||||||
|
return myOperationOutcome;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "ValidationResult{" +
|
||||||
|
"myOperationOutcome=" + myOperationOutcome +
|
||||||
|
", description='" + toDescription() + '\'' +
|
||||||
|
'}';
|
||||||
|
}
|
||||||
|
|
||||||
|
private String toDescription() {
|
||||||
|
StringBuilder b = new StringBuilder(100);
|
||||||
|
if (myOperationOutcome != null) {
|
||||||
|
OperationOutcome.Issue issueFirstRep = myOperationOutcome.getIssueFirstRep();
|
||||||
|
b.append(issueFirstRep.getDetails().getValue());
|
||||||
|
b.append(" - ");
|
||||||
|
b.append(issueFirstRep.getLocationFirstRep().getValue());
|
||||||
|
}
|
||||||
|
return b.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Was the validation successful
|
||||||
|
* @return true if the validation was successful
|
||||||
|
*/
|
||||||
|
public boolean isSuccessful() {
|
||||||
|
return myOperationOutcome == null || myOperationOutcome.getIssue().isEmpty();
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,17 +1,22 @@
|
||||||
package ca.uhn.fhir.validation;
|
package ca.uhn.fhir.validation;
|
||||||
|
|
||||||
import static org.hamcrest.Matchers.*;
|
|
||||||
import static org.junit.Assert.*;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
|
|
||||||
import org.apache.commons.io.IOUtils;
|
|
||||||
import org.junit.Test;
|
|
||||||
|
|
||||||
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.dstu.resource.OperationOutcome;
|
||||||
import ca.uhn.fhir.model.dstu.resource.Patient;
|
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 org.apache.commons.io.IOUtils;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
import static org.hamcrest.Matchers.containsString;
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.assertFalse;
|
||||||
|
import static org.junit.Assert.assertNotNull;
|
||||||
|
import static org.junit.Assert.assertThat;
|
||||||
|
import static org.junit.Assert.assertTrue;
|
||||||
|
import static org.junit.Assert.fail;
|
||||||
|
|
||||||
public class ResourceValidatorTest {
|
public class ResourceValidatorTest {
|
||||||
|
|
||||||
|
@ -45,9 +50,7 @@ public class ResourceValidatorTest {
|
||||||
String res = IOUtils.toString(getClass().getClassLoader().getResourceAsStream("atom-document-large.xml"));
|
String res = IOUtils.toString(getClass().getClassLoader().getResourceAsStream("atom-document-large.xml"));
|
||||||
Bundle b = ourCtx.newXmlParser().parseBundle(res);
|
Bundle b = ourCtx.newXmlParser().parseBundle(res);
|
||||||
|
|
||||||
FhirValidator val = ourCtx.newValidator();
|
FhirValidator val = createFhirValidator();
|
||||||
val.setValidateAgainstStandardSchema(true);
|
|
||||||
val.setValidateAgainstStandardSchematron(true);
|
|
||||||
|
|
||||||
val.validate(b);
|
val.validate(b);
|
||||||
|
|
||||||
|
@ -64,7 +67,6 @@ public class ResourceValidatorTest {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testSchematronResourceValidator() throws IOException {
|
public void testSchematronResourceValidator() throws IOException {
|
||||||
String res = IOUtils.toString(getClass().getClassLoader().getResourceAsStream("patient-example-dicom.xml"));
|
String res = IOUtils.toString(getClass().getClassLoader().getResourceAsStream("patient-example-dicom.xml"));
|
||||||
|
@ -74,20 +76,60 @@ public class ResourceValidatorTest {
|
||||||
val.setValidateAgainstStandardSchema(false);
|
val.setValidateAgainstStandardSchema(false);
|
||||||
val.setValidateAgainstStandardSchematron(true);
|
val.setValidateAgainstStandardSchematron(true);
|
||||||
|
|
||||||
val.validate(p);
|
ValidationResult validationResult = val.validateWithResult(p);
|
||||||
|
assertTrue(validationResult.isSuccessful());
|
||||||
|
|
||||||
p.getTelecomFirstRep().setValue("123-4567");
|
p.getTelecomFirstRep().setValue("123-4567");
|
||||||
try {
|
validationResult = val.validateWithResult(p);
|
||||||
val.validate(p);
|
assertFalse(validationResult.isSuccessful());
|
||||||
fail();
|
OperationOutcome operationOutcome = validationResult.getOperationOutcome();
|
||||||
} catch (ValidationFailureException e) {
|
ourLog.info(ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(operationOutcome));
|
||||||
ourLog.info(ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(e.getOperationOutcome()));
|
assertEquals(1, operationOutcome.getIssue().size());
|
||||||
assertEquals(1, e.getOperationOutcome().getIssue().size());
|
assertThat(operationOutcome.getIssueFirstRep().getDetails().getValue(), containsString("Inv-2: A system is required if a value is provided."));
|
||||||
assertThat(e.getOperationOutcome().getIssueFirstRep().getDetails().getValue(), containsString("Inv-2: A system is required if a value is provided."));
|
|
||||||
}
|
|
||||||
|
|
||||||
p.getTelecomFirstRep().setSystem(ContactSystemEnum.EMAIL);
|
p.getTelecomFirstRep().setSystem(ContactSystemEnum.EMAIL);
|
||||||
val.validate(p);
|
validationResult = val.validateWithResult(p);
|
||||||
|
assertTrue(validationResult.isSuccessful());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSchemaBundleValidatorIsSuccessful() throws IOException {
|
||||||
|
String res = IOUtils.toString(getClass().getClassLoader().getResourceAsStream("atom-document-large.xml"));
|
||||||
|
Bundle b = ourCtx.newXmlParser().parseBundle(res);
|
||||||
|
|
||||||
|
FhirValidator val = createFhirValidator();
|
||||||
|
|
||||||
|
ValidationResult result = val.validateWithResult(b);
|
||||||
|
assertTrue(result.isSuccessful());
|
||||||
|
OperationOutcome operationOutcome = result.getOperationOutcome();
|
||||||
|
assertNotNull(operationOutcome);
|
||||||
|
assertEquals(0, operationOutcome.getIssue().size());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSchemaBundleValidatorFails() throws IOException {
|
||||||
|
String res = IOUtils.toString(getClass().getClassLoader().getResourceAsStream("atom-document-large.xml"));
|
||||||
|
Bundle b = ourCtx.newXmlParser().parseBundle(res);
|
||||||
|
|
||||||
|
FhirValidator val = createFhirValidator();
|
||||||
|
|
||||||
|
ValidationResult validationResult = val.validateWithResult(b);
|
||||||
|
assertTrue(validationResult.isSuccessful());
|
||||||
|
|
||||||
|
Patient p = (Patient) b.getEntries().get(0).getResource();
|
||||||
|
p.getTelecomFirstRep().setValue("123-4567");
|
||||||
|
validationResult = val.validateWithResult(b);
|
||||||
|
assertFalse(validationResult.isSuccessful());
|
||||||
|
OperationOutcome operationOutcome = validationResult.getOperationOutcome();
|
||||||
|
ourLog.info(ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(operationOutcome));
|
||||||
|
assertEquals(1, operationOutcome.getIssue().size());
|
||||||
|
assertThat(operationOutcome.getIssueFirstRep().getDetails().getValue(), containsString("Inv-2: A system is required if a value is provided."));
|
||||||
|
}
|
||||||
|
|
||||||
|
private FhirValidator createFhirValidator() {
|
||||||
|
FhirValidator val = ourCtx.newValidator();
|
||||||
|
val.setValidateAgainstStandardSchema(true);
|
||||||
|
val.setValidateAgainstStandardSchematron(true);
|
||||||
|
return val;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,46 @@
|
||||||
|
package ca.uhn.fhir.validation;
|
||||||
|
|
||||||
|
import ca.uhn.fhir.model.dstu.resource.OperationOutcome;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
import static org.hamcrest.Matchers.containsString;
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.assertFalse;
|
||||||
|
import static org.junit.Assert.assertThat;
|
||||||
|
import static org.junit.Assert.assertTrue;
|
||||||
|
|
||||||
|
public class ValidationResultTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void isSuccessful_IsTrueForNullOperationOutcome() {
|
||||||
|
ValidationResult result = ValidationResult.valueOf(null);
|
||||||
|
assertTrue(result.isSuccessful());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void isSuccessful_IsTrueForNoIssues() {
|
||||||
|
OperationOutcome operationOutcome = new OperationOutcome();
|
||||||
|
// make sure a non-null ID doesn't cause the validation result to be a fail
|
||||||
|
operationOutcome.setId(UUID.randomUUID().toString());
|
||||||
|
ValidationResult result = ValidationResult.valueOf(operationOutcome);
|
||||||
|
assertTrue(result.isSuccessful());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void isSuccessful_FalseForIssues() {
|
||||||
|
OperationOutcome operationOutcome = new OperationOutcome();
|
||||||
|
OperationOutcome.Issue issue = operationOutcome.addIssue();
|
||||||
|
String errorMessage = "There was a validation problem";
|
||||||
|
issue.setDetails(errorMessage);
|
||||||
|
ValidationResult result = ValidationResult.valueOf(operationOutcome);
|
||||||
|
assertFalse(result.isSuccessful());
|
||||||
|
List<OperationOutcome.Issue> issues = result.getOperationOutcome().getIssue();
|
||||||
|
assertEquals(1, issues.size());
|
||||||
|
assertEquals(errorMessage, issues.get(0).getDetails().getValue());
|
||||||
|
|
||||||
|
assertThat("ValidationResult#toString should contain the issue description", result.toString(), containsString(errorMessage));
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue