Avoid error when unknown code system behaviour set to warning (#3436)

* Avoid error when unknown code system behaviour set to warning

* Add changelog

* Test fix

* Build fix

* Fixes

* Address review comment
This commit is contained in:
James Agnew 2022-03-01 12:30:59 -05:00 committed by GitHub
parent 2cba62b4e8
commit f614eaf6c8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 281 additions and 100 deletions

View File

@ -0,0 +1,7 @@
---
type: fix
issue: 3436
jira: SMILE-3563
title: "A regression in HAPI FHIR 5.7.0 meant that when UnknownCodeSystemWarningValidationSupport was
configured for WARNING behaviour, validating a field with an implicit code system could
incorrectly result in an error."

View File

@ -75,16 +75,17 @@ public class JpaValidationSupportChain extends ValidationSupportChain {
@PostConstruct
public void postConstruct() {
addValidationSupport(myUnknownCodeSystemWarningValidationSupport);
addValidationSupport(myDefaultProfileValidationSupport);
addValidationSupport(myJpaValidationSupport);
//TODO MAKE SURE THAT THIS IS BEING CAL
addValidationSupport(myTerminologyService);
addValidationSupport(new SnapshotGeneratingValidationSupport(myFhirContext));
addValidationSupport(new InMemoryTerminologyServerValidationSupport(myFhirContext));
addValidationSupport(myNpmJpaValidationSupport);
addValidationSupport(new CommonCodeSystemsTerminologyService(myFhirContext));
addValidationSupport(myConceptMappingSvc);
// This needs to be last in the chain, it was designed for that
addValidationSupport(myUnknownCodeSystemWarningValidationSupport);
}
}

View File

@ -36,6 +36,7 @@ import org.hl7.fhir.instance.model.api.IBaseOperationOutcome;
import org.hl7.fhir.instance.model.api.IBaseResource;
import org.hl7.fhir.instance.model.api.IIdType;
import org.hl7.fhir.r4.model.AllergyIntolerance;
import org.hl7.fhir.r4.model.Binary;
import org.hl7.fhir.r4.model.Bundle;
import org.hl7.fhir.r4.model.Bundle.BundleEntryComponent;
import org.hl7.fhir.r4.model.CanonicalType;
@ -125,23 +126,11 @@ public class FhirResourceDaoR4ValidateTest extends BaseJpaR4Test {
myUnknownCodeSystemWarningValidationSupport.setNonExistentCodeSystemSeverity(UnknownCodeSystemWarningValidationSupport.DEFAULT_SEVERITY);
}
/**
* By default an unknown code system should fail vaildation
*/
@Test
public void testValidateCodeInValueSetWithUnknownCodeSystem_FailValidation() {
createStructureDefWithBindingToUnknownCs();
createStructureDefWithBindingToUnknownCs(true);
Observation obs = new Observation();
obs.getMeta().addProfile("http://sd");
obs.getText().setDivAsString("<div>Hello</div>");
obs.getText().setStatus(Narrative.NarrativeStatus.GENERATED);
obs.getCategoryFirstRep().addCoding().setSystem("http://terminology.hl7.org/CodeSystem/observation-category").setCode("vital-signs");
obs.getCode().setText("hello");
obs.setSubject(new Reference("Patient/123"));
obs.addPerformer(new Reference("Practitioner/123"));
obs.setEffective(DateTimeType.now());
obs.setStatus(ObservationStatus.FINAL);
Observation obs = createObservationForUnknownCodeSystemTest();
OperationOutcome oo;
@ -163,6 +152,210 @@ public class FhirResourceDaoR4ValidateTest extends BaseJpaR4Test {
}
@Test
public void testValidateCodeInEnumeratedValueSetWithUnknownCodeSystem_Information() {
myUnknownCodeSystemWarningValidationSupport.setNonExistentCodeSystemSeverity(IValidationSupport.IssueSeverity.INFORMATION);
createStructureDefWithBindingToUnknownCs(true);
Observation obs = createObservationForUnknownCodeSystemTest();
OperationOutcome oo;
String encoded;
// Valid code
obs.setValue(new Quantity().setSystem("http://cs").setCode("code1").setValue(123));
oo = validateAndReturnOutcome(obs, false);
encoded = encode(oo);
ourLog.info(encoded);
assertEquals(1, oo.getIssue().size());
assertEquals("No issues detected during validation", oo.getIssueFirstRep().getDiagnostics());
assertEquals(OperationOutcome.IssueSeverity.INFORMATION, oo.getIssueFirstRep().getSeverity());
// Invalid code
obs.setValue(new Quantity().setSystem("http://cs").setCode("code99").setValue(123));
oo = validateAndReturnOutcome(obs, true);
encoded = encode(oo);
ourLog.info(encoded);
assertEquals(1, oo.getIssue().size());
assertEquals("The code provided (http://cs#code99) is not in the value set http://vs, and a code from this value set is required: Unknown code 'http://cs#code99' for in-memory expansion of ValueSet 'http://vs'", oo.getIssueFirstRep().getDiagnostics());
assertEquals(OperationOutcome.IssueSeverity.ERROR, oo.getIssueFirstRep().getSeverity());
}
/**
* By default, an unknown code system should fail validation
*/
@Test
public void testValidateCodeInEnumeratedValueSetWithUnknownCodeSystem_Warning() {
// set to warning
myUnknownCodeSystemWarningValidationSupport.setNonExistentCodeSystemSeverity(IValidationSupport.IssueSeverity.WARNING);
createStructureDefWithBindingToUnknownCs(true);
Observation obs = createObservationForUnknownCodeSystemTest();
OperationOutcome oo;
String encoded;
// Valid code
obs.setValue(new Quantity().setSystem("http://cs").setCode("code1").setValue(123));
oo = validateAndReturnOutcome(obs, false);
encoded = encode(oo);
ourLog.info(encoded);
assertEquals(1, oo.getIssue().size());
assertEquals("CodeSystem is unknown and can't be validated: http://cs for 'http://cs#code1'", oo.getIssueFirstRep().getDiagnostics());
assertEquals(OperationOutcome.IssueSeverity.WARNING, oo.getIssueFirstRep().getSeverity());
// Invalid code
obs.setValue(new Quantity().setSystem("http://cs").setCode("code99").setValue(123));
oo = validateAndReturnOutcome(obs, true);
encoded = encode(oo);
ourLog.info(encoded);
assertEquals(2, oo.getIssue().size());
assertEquals("CodeSystem is unknown and can't be validated: http://cs for 'http://cs#code99'", oo.getIssue().get(0).getDiagnostics());
assertEquals(OperationOutcome.IssueSeverity.WARNING, oo.getIssue().get(0).getSeverity());
assertEquals("The code provided (http://cs#code99) is not in the value set http://vs, and a code from this value set is required: Unknown code 'http://cs#code99' for in-memory expansion of ValueSet 'http://vs'", oo.getIssue().get(1).getDiagnostics());
assertEquals(OperationOutcome.IssueSeverity.ERROR, oo.getIssue().get(1).getSeverity());
}
@Test
public void testValidateCodeInEnumeratedValueSetWithUnknownCodeSystem_Error() {
myUnknownCodeSystemWarningValidationSupport.setNonExistentCodeSystemSeverity(IValidationSupport.IssueSeverity.ERROR);
createStructureDefWithBindingToUnknownCs(true);
Observation obs = new Observation();
obs.getMeta().addProfile("http://sd");
obs.getText().setDivAsString("<div>Hello</div>");
obs.getText().setStatus(Narrative.NarrativeStatus.GENERATED);
obs.getCategoryFirstRep().addCoding().setSystem("http://terminology.hl7.org/CodeSystem/observation-category").setCode("vital-signs");
obs.getCode().setText("hello");
obs.setSubject(new Reference("Patient/123"));
obs.addPerformer(new Reference("Practitioner/123"));
obs.setEffective(DateTimeType.now());
obs.setStatus(ObservationStatus.FINAL);
OperationOutcome oo;
String encoded;
// Valid code
obs.setValue(new Quantity().setSystem("http://cs").setCode("code1").setValue(123));
oo = validateAndReturnOutcome(obs, false);
encoded = encode(oo);
ourLog.info(encoded);
assertEquals(1, oo.getIssue().size());
assertTrue(oo.getIssueFirstRep().getDiagnostics().contains("No issues detected during validation"));
assertEquals(OperationOutcome.IssueSeverity.INFORMATION, oo.getIssueFirstRep().getSeverity());
// Invalid code
obs.setValue(new Quantity().setSystem("http://cs").setCode("code99").setValue(123));
oo = validateAndReturnOutcome(obs, true);
encoded = encode(oo);
ourLog.info(encoded);
assertEquals(1, oo.getIssue().size());
assertTrue(oo.getIssueFirstRep()
.getDiagnostics().contains("The code provided (http://cs#code99) is not in the value set http://vs, and a code from this value set is required: Unknown code 'http://cs#code99' for in-memory expansion of ValueSet 'http://vs'")
);
assertEquals(OperationOutcome.IssueSeverity.ERROR, oo.getIssueFirstRep().getSeverity());
}
@Test
public void testValidateCodeInNonEnumeratedValueSetWithUnknownCodeSystem_Information() {
myUnknownCodeSystemWarningValidationSupport.setNonExistentCodeSystemSeverity(IValidationSupport.IssueSeverity.INFORMATION);
createStructureDefWithBindingToUnknownCs(false);
Observation obs = createObservationForUnknownCodeSystemTest();
OperationOutcome oo;
String encoded;
// Valid code
obs.setValue(new Quantity().setSystem("http://cs").setCode("code1").setValue(123));
oo = validateAndReturnOutcome(obs, false);
encoded = encode(oo);
ourLog.info(encoded);
assertEquals(1, oo.getIssue().size());
assertEquals("No issues detected during validation", oo.getIssueFirstRep().getDiagnostics());
assertEquals(OperationOutcome.IssueSeverity.INFORMATION, oo.getIssueFirstRep().getSeverity());
// Invalid code
obs.setValue(new Quantity().setSystem("http://cs").setCode("code99").setValue(123));
oo = validateAndReturnOutcome(obs, false);
encoded = encode(oo);
ourLog.info(encoded);
assertEquals(1, oo.getIssue().size());
assertEquals("No issues detected during validation", oo.getIssueFirstRep().getDiagnostics());
assertEquals(OperationOutcome.IssueSeverity.INFORMATION, oo.getIssueFirstRep().getSeverity());
}
/**
* By default, an unknown code system should fail validation
*/
@Test
public void testValidateCodeInNonEnumeratedValueSetWithUnknownCodeSystem_Warning() {
// set to warning
myUnknownCodeSystemWarningValidationSupport.setNonExistentCodeSystemSeverity(IValidationSupport.IssueSeverity.WARNING);
createStructureDefWithBindingToUnknownCs(false);
Observation obs = createObservationForUnknownCodeSystemTest();
OperationOutcome oo;
String encoded;
// Valid code
obs.setValue(new Quantity().setSystem("http://cs").setCode("code1").setValue(123));
oo = validateAndReturnOutcome(obs, false);
encoded = encode(oo);
ourLog.info(encoded);
assertEquals(1, oo.getIssue().size());
assertEquals("CodeSystem is unknown and can't be validated: http://cs for 'http://cs#code1'", oo.getIssueFirstRep().getDiagnostics());
assertEquals(OperationOutcome.IssueSeverity.WARNING, oo.getIssueFirstRep().getSeverity());
// Invalid code
obs.setValue(new Quantity().setSystem("http://cs").setCode("code99").setValue(123));
oo = validateAndReturnOutcome(obs, false);
encoded = encode(oo);
ourLog.info(encoded);
assertEquals(1, oo.getIssue().size());
assertEquals("CodeSystem is unknown and can't be validated: http://cs for 'http://cs#code99'", oo.getIssue().get(0).getDiagnostics());
assertEquals(OperationOutcome.IssueSeverity.WARNING, oo.getIssue().get(0).getSeverity());
}
@Test
public void testValidateCodeInNonEnumeratedValueSetWithUnknownCodeSystem_Error() {
myUnknownCodeSystemWarningValidationSupport.setNonExistentCodeSystemSeverity(IValidationSupport.IssueSeverity.ERROR);
createStructureDefWithBindingToUnknownCs(false);
Observation obs = new Observation();
obs.getMeta().addProfile("http://sd");
obs.getText().setDivAsString("<div>Hello</div>");
obs.getText().setStatus(Narrative.NarrativeStatus.GENERATED);
obs.getCategoryFirstRep().addCoding().setSystem("http://terminology.hl7.org/CodeSystem/observation-category").setCode("vital-signs");
obs.getCode().setText("hello");
obs.setSubject(new Reference("Patient/123"));
obs.addPerformer(new Reference("Practitioner/123"));
obs.setEffective(DateTimeType.now());
obs.setStatus(ObservationStatus.FINAL);
OperationOutcome oo;
String encoded;
// Valid code
obs.setValue(new Quantity().setSystem("http://cs").setCode("code1").setValue(123));
oo = validateAndReturnOutcome(obs, true);
encoded = encode(oo);
ourLog.info(encoded);
assertEquals(1, oo.getIssue().size());
assertEquals("The code provided (http://cs#code1) is not in the value set http://vs, and a code from this value set is required: Failed to expand ValueSet 'http://vs' (in-memory). Could not validate code http://cs#code1. Error was: HAPI-0702: Unable to expand ValueSet because CodeSystem could not be found: http://cs", oo.getIssueFirstRep().getDiagnostics());
assertEquals(OperationOutcome.IssueSeverity.ERROR, oo.getIssueFirstRep().getSeverity());
}
private Observation createObservationForUnknownCodeSystemTest() {
Observation obs = new Observation();
obs.getMeta().addProfile("http://sd");
@ -177,85 +370,60 @@ public class FhirResourceDaoR4ValidateTest extends BaseJpaR4Test {
return obs;
}
/**
* By default, an unknown code system should fail validation
*/
@Test
public void testValidateCodeInValueSetWithUnknownCodeSystem_Warning() {
public void testValidateCodeInValueSet_InferredCodeSystem_WarningOnUnknown() {
// set to warning
myUnknownCodeSystemWarningValidationSupport.setNonExistentCodeSystemSeverity(IValidationSupport.IssueSeverity.WARNING);
createStructureDefWithBindingToUnknownCs();
Observation obs = createObservationForUnknownCodeSystemTest();
OperationOutcome oo;
String encoded;
Binary binary = new Binary();
binary.setContentType("application/text");
binary.setContent("hello".getBytes(StandardCharsets.UTF_8));
// Valid code
obs.setValue(new Quantity().setSystem("http://cs").setCode("code1").setValue(123));
oo = validateAndReturnOutcome(obs);
oo = validateAndReturnOutcome(binary);
encoded = encode(oo);
ourLog.info(encoded);
assertTrue(oo.getIssueFirstRep().getDiagnostics().contains("No issues detected during validation"));
// Invalid code
obs.setValue(new Quantity().setSystem("http://cs").setCode("code99").setValue(123));
oo = validateAndReturnOutcome(obs);
encoded = encode(oo);
ourLog.info(encoded);
assertTrue(oo.getIssueFirstRep().getDiagnostics().contains("No issues detected during validation"));
}
@Test
public void testValidateCodeInValueSetWithUnknownCodeSystem_Error() {
public void testValidateCodeInValueSet_InferredCodeSystem_ErrorOnUnknown() {
// set to warning
myUnknownCodeSystemWarningValidationSupport.setNonExistentCodeSystemSeverity(IValidationSupport.IssueSeverity.ERROR);
createStructureDefWithBindingToUnknownCs();
Observation obs = new Observation();
obs.getMeta().addProfile("http://sd");
obs.getText().setDivAsString("<div>Hello</div>");
obs.getText().setStatus(Narrative.NarrativeStatus.GENERATED);
obs.getCategoryFirstRep().addCoding().setSystem("http://terminology.hl7.org/CodeSystem/observation-category").setCode("vital-signs");
obs.getCode().setText("hello");
obs.setSubject(new Reference("Patient/123"));
obs.addPerformer(new Reference("Practitioner/123"));
obs.setEffective(DateTimeType.now());
obs.setStatus(ObservationStatus.FINAL);
OperationOutcome oo;
String encoded;
Binary binary = new Binary();
binary.setContentType("application/text");
binary.setContent("hello".getBytes(StandardCharsets.UTF_8));
// Valid code
obs.setValue(new Quantity().setSystem("http://cs").setCode("code1").setValue(123));
oo = validateAndReturnOutcome(obs);
oo = validateAndReturnOutcome(binary);
encoded = encode(oo);
ourLog.info(encoded);
assertTrue(oo.getIssueFirstRep().getDiagnostics().contains("No issues detected during validation"));
// Invalid code
obs.setValue(new Quantity().setSystem("http://cs").setCode("code99").setValue(123));
oo = validateAndReturnOutcome(obs);
encoded = encode(oo);
ourLog.info(encoded);
assertTrue(oo.getIssueFirstRep()
.getDiagnostics().contains("The code provided (http://cs#code99) is not in the value set http://vs, and a code from this value set is required: Unknown code 'http://cs#code99' for in-memory expansion of ValueSet 'http://vs'")
);
}
public void createStructureDefWithBindingToUnknownCs() {
public void createStructureDefWithBindingToUnknownCs(boolean theEnumeratedCodeSystem) {
myValidationSupport.fetchCodeSystem("http://not-exist"); // preload DefaultProfileValidationSupport
ValueSet vs = new ValueSet();
vs.setUrl("http://vs");
vs
ValueSet.ConceptSetComponent include = vs
.getCompose()
.addInclude()
.setSystem("http://cs")
.addConcept(new ValueSet.ConceptReferenceComponent(new CodeType("code1")))
.addConcept(new ValueSet.ConceptReferenceComponent(new CodeType("code2")));
.setSystem("http://cs");
if (theEnumeratedCodeSystem) {
include.addConcept(new ValueSet.ConceptReferenceComponent(new CodeType("code1")));
include.addConcept(new ValueSet.ConceptReferenceComponent(new CodeType("code2")));
}
myValueSetDao.create(vs);
StructureDefinition sd = new StructureDefinition();
@ -1105,6 +1273,17 @@ public class FhirResourceDaoR4ValidateTest extends BaseJpaR4Test {
}
}
private <T extends IBaseResource> OperationOutcome validateAndReturnOutcome(T theObs, Boolean theWantError) {
IFhirResourceDao<T> dao = (IFhirResourceDao<T>) myDaoRegistry.getResourceDao(theObs.getClass());
try {
MethodOutcome outcome = dao.validate(theObs, null, null, null, ValidationModeEnum.CREATE, null, mySrd);
assertTrue(theWantError == null || !theWantError, "Wanted an error response but got a non-error");
return (OperationOutcome) outcome.getOperationOutcome();
} catch (PreconditionFailedException e) {
assertTrue(theWantError == null || theWantError, "Wanted a non-error response but got an error");
return (OperationOutcome) e.getOperationOutcome();
}
}
@Test
public void testValidateStructureDefinition() throws Exception {
@ -1140,6 +1319,9 @@ public class FhirResourceDaoR4ValidateTest extends BaseJpaR4Test {
ourLog.info("Starting validation");
try {
MethodOutcome outcome = myBundleDao.validate(document, null, null, null, ValidationModeEnum.CREATE, null, mySrd);
String encodedResponse = myFhirContext.newJsonParser().encodeResourceToString(outcome.getOperationOutcome());
ourLog.info("Validation result: {}", encodedResponse);
fail();
} catch (PreconditionFailedException e) {
ourLog.info(myFhirContext.newJsonParser().setPrettyPrint(true).encodeResourceToString(e.getOperationOutcome()));
}

View File

@ -77,24 +77,6 @@ public class HttpProxyTest {
int port = JettyUtil.getPortForStartedServer(server);
try {
// final String authUser = "username";
// final String authPassword = "password";
// CredentialsProvider credsProvider = new BasicCredentialsProvider();
// credsProvider.setCredentials(new AuthScope("127.0.0.1", port), new UsernamePasswordCredentials(authUser, authPassword));
//
// HttpHost myProxy = new HttpHost("127.0.0.1", port);
//
// //@formatter:off
// HttpClientBuilder clientBuilder = HttpClientBuilder.create();
// clientBuilder
// .setProxy(myProxy)
// .setProxyAuthenticationStrategy(new ProxyAuthenticationStrategy())
// .setDefaultCredentialsProvider(credsProvider)
// .disableCookieManagement();
// CloseableHttpClient httpClient = clientBuilder.build();
// //@formatter:on
// ourCtx.getRestfulClientFactory().setHttpClient(httpClient);
ourCtx.getRestfulClientFactory().setProxy("127.0.0.1", port);
ourCtx.getRestfulClientFactory().setProxyCredentials("username", "password");

View File

@ -34,6 +34,9 @@ import java.net.URL;
public class HtmlUtil {
private HtmlUtil() {
}
public static HtmlPage parseAsHtml(String theRespString, URL theUrl) throws IOException {
StringWebResponse response = new StringWebResponse(theRespString, theUrl);
WebClient client = new WebClient(BrowserVersion.BEST_SUPPORTED, false, null, -1);
@ -42,7 +45,7 @@ public class HtmlUtil {
final HtmlPage page = new HtmlPage(response, client.getCurrentWindow());
HtmlUnitNekoHtmlParser htmlUnitNekoHtmlParser = new HtmlUnitNekoHtmlParser();
htmlUnitNekoHtmlParser.parse(response, page, false);
htmlUnitNekoHtmlParser.parse(response, page, false, false);
return page;
}

View File

@ -3,6 +3,7 @@ package org.hl7.fhir.common.hapi.validation.support;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.context.support.ConceptValidationOptions;
import ca.uhn.fhir.context.support.ValidationSupportContext;
import org.apache.commons.lang3.Validate;
import org.hl7.fhir.instance.model.api.IBaseResource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -42,28 +43,35 @@ public class UnknownCodeSystemWarningValidationSupport extends BaseValidationSup
return canValidateCodeSystem(theValidationSupportContext, theSystem);
}
@Nullable
@Override
public LookupCodeResult lookupCode(ValidationSupportContext theValidationSupportContext, String theSystem, String theCode, String theDisplayLanguage) {
// filters out error/fatal
if (canValidateCodeSystem(theValidationSupportContext, theSystem)) {
return new LookupCodeResult()
.setFound(true);
}
return null;
}
@Override
public CodeValidationResult validateCode(@Nonnull ValidationSupportContext theValidationSupportContext, @Nonnull ConceptValidationOptions theOptions, String theCodeSystem, String theCode, String theDisplay, String theValueSetUrl) {
// filters out error/fatal
// NB: this is a secondary check. isCodeSystemSupported
// should prevent this from ever calling validate code here
// ... but should it ever get called, we'll return null
if (!canValidateCodeSystem(theValidationSupportContext, theCodeSystem)) {
return null;
}
CodeValidationResult result = new CodeValidationResult()
.setSeverity(myNonExistentCodeSystemSeverity); // will be warning or info (error/fatal filtered out above)
CodeValidationResult result = new CodeValidationResult();
// will be warning or info (error/fatal filtered out above)
result.setSeverity(myNonExistentCodeSystemSeverity);
result.setMessage("CodeSystem is unknown and can't be validated: " + theCodeSystem);
result.setMessage("No issues detected during validation");
switch (myNonExistentCodeSystemSeverity) {
case INFORMATION:
// for warnings, we don't set the code
// cause if we do, the severity is stripped out
// (see VersionSpecificWorkerContextWrapper.convertValidationResult)
result.setCode(theCode);
break;
if (myNonExistentCodeSystemSeverity == IssueSeverity.INFORMATION) {
// for warnings, we don't set the code
// cause if we do, the severity is stripped out
// (see VersionSpecificWorkerContextWrapper.convertValidationResult)
result.setCode(theCode);
}
return result;
@ -126,8 +134,6 @@ public class UnknownCodeSystemWarningValidationSupport extends BaseValidationSup
/**
* If set to allow, code system violations will be flagged with Warning by default.
* Use setNonExistentCodeSystemSeverity instead.
*
* @param theAllowNonExistentCodeSystem
*/
@Deprecated
public void setAllowNonExistentCodeSystem(boolean theAllowNonExistentCodeSystem) {
@ -140,9 +146,9 @@ public class UnknownCodeSystemWarningValidationSupport extends BaseValidationSup
/**
* Sets the non-existent code system severity.
* @param theSeverity
*/
public void setNonExistentCodeSystemSeverity(IssueSeverity theSeverity) {
public void setNonExistentCodeSystemSeverity(@Nonnull IssueSeverity theSeverity) {
Validate.notNull(theSeverity, "theSeverity must not be null");
myNonExistentCodeSystemSeverity = theSeverity;
}
}

View File

@ -1197,7 +1197,7 @@
<dependency>
<groupId>net.sourceforge.htmlunit</groupId>
<artifactId>htmlunit</artifactId>
<version>2.56.0</version>
<version>2.58.0</version>
</dependency>
<dependency>
<groupId>net.sf.json-lib</groupId>