Fix crash in JPA server if numeric search parameter has no value

This commit is contained in:
James 2017-06-11 09:16:48 -04:00
parent c2e5fa3f18
commit a50a86d9af
3 changed files with 79 additions and 26 deletions

View File

@ -76,13 +76,6 @@ import ca.uhn.fhir.context.RuntimeChildChoiceDefinition;
import ca.uhn.fhir.context.RuntimeChildResourceDefinition; import ca.uhn.fhir.context.RuntimeChildResourceDefinition;
import ca.uhn.fhir.context.RuntimeResourceDefinition; import ca.uhn.fhir.context.RuntimeResourceDefinition;
import ca.uhn.fhir.context.RuntimeSearchParam; import ca.uhn.fhir.context.RuntimeSearchParam;
import ca.uhn.fhir.jpa.dao.BaseHapiFhirDao;
import ca.uhn.fhir.jpa.dao.BaseHapiFhirResourceDao;
import ca.uhn.fhir.jpa.dao.IDao;
import ca.uhn.fhir.jpa.dao.IFhirResourceDao;
import ca.uhn.fhir.jpa.dao.IFulltextSearchSvc;
import ca.uhn.fhir.jpa.dao.ISearchBuilder;
import ca.uhn.fhir.jpa.dao.ISearchParamRegistry;
import ca.uhn.fhir.jpa.dao.data.IForcedIdDao; import ca.uhn.fhir.jpa.dao.data.IForcedIdDao;
import ca.uhn.fhir.jpa.dao.data.IResourceIndexedSearchParamUriDao; import ca.uhn.fhir.jpa.dao.data.IResourceIndexedSearchParamUriDao;
import ca.uhn.fhir.jpa.entity.BaseHasResource; import ca.uhn.fhir.jpa.entity.BaseHasResource;
@ -1102,7 +1095,7 @@ public class SearchBuilder implements ISearchBuilder {
if (!isBlank(unitsValue)) { if (!isBlank(unitsValue)) {
code = theBuilder.equal(theFrom.get("myUnits"), unitsValue); code = theBuilder.equal(theFrom.get("myUnits"), unitsValue);
} }
cmpValue = ObjectUtils.defaultIfNull(cmpValue, ParamPrefixEnum.EQUAL); cmpValue = ObjectUtils.defaultIfNull(cmpValue, ParamPrefixEnum.EQUAL);
final Expression<BigDecimal> path = theFrom.get("myValue"); final Expression<BigDecimal> path = theFrom.get("myValue");
String invalidMessageName = "invalidQuantityPrefix"; String invalidMessageName = "invalidQuantityPrefix";
@ -1768,6 +1761,39 @@ public class SearchBuilder implements ISearchBuilder {
} }
private void searchForIdsWithAndOr(String theResourceName, String theParamName, List<List<? extends IQueryParameterType>> theAndOrParams) { private void searchForIdsWithAndOr(String theResourceName, String theParamName, List<List<? extends IQueryParameterType>> theAndOrParams) {
for (int andListIdx = 0; andListIdx < theAndOrParams.size(); andListIdx++) {
List<? extends IQueryParameterType> nextOrList = theAndOrParams.get(andListIdx);
for (int orListIdx = 0; orListIdx < nextOrList.size(); orListIdx++) {
IQueryParameterType nextOr = nextOrList.get(orListIdx);
boolean hasNoValue = false;
if (nextOr.getMissing() != null) {
continue;
}
if (nextOr instanceof QuantityParam) {
if (isBlank(((QuantityParam) nextOr).getValueAsString())) {
hasNoValue = true;
}
}
if (hasNoValue) {
ourLog.debug("Ignoring empty parameter: {}", theParamName);
nextOrList.remove(orListIdx);
orListIdx--;
}
}
if (nextOrList.isEmpty()) {
theAndOrParams.remove(andListIdx);
andListIdx--;
}
}
if (theAndOrParams.isEmpty()) {
return;
}
if (theParamName.equals(BaseResource.SP_RES_ID)) { if (theParamName.equals(BaseResource.SP_RES_ID)) {
addPredicateResourceId(theAndOrParams); addPredicateResourceId(theAndOrParams);

View File

@ -178,14 +178,41 @@ public class ResourceProviderDstu3Test extends BaseResourceProviderDstu3Test {
myDaoConfig.setAllowMultipleDelete(true); myDaoConfig.setAllowMultipleDelete(true);
} }
@Test
public void testSearchWithEmptyParameter() throws Exception {
Observation obs= new Observation();
obs.setStatus(ObservationStatus.FINAL);
obs.getCode().addCoding().setSystem("foo").setCode("bar");
ourClient.create().resource(obs).execute();
testSearchWithEmptyParameter("/Observation?value-quantity=");
testSearchWithEmptyParameter("/Observation?code=bar&value-quantity=");
testSearchWithEmptyParameter("/Observation?value-date=");
testSearchWithEmptyParameter("/Observation?code=bar&value-date=");
testSearchWithEmptyParameter("/Observation?value-concept=");
testSearchWithEmptyParameter("/Observation?code=bar&value-concept=");
}
private void testSearchWithEmptyParameter(String url) throws IOException, ClientProtocolException {
HttpGet get = new HttpGet(ourServerBase + url);
CloseableHttpResponse resp = ourHttpClient.execute(get);
try {
assertEquals(200, resp.getStatusLine().getStatusCode());
String respString = IOUtils.toString(resp.getEntity().getContent(), Constants.CHARSET_UTF8);
Bundle bundle = myFhirCtx.newXmlParser().parseResource(Bundle.class, respString);
assertEquals(1, bundle.getEntry().size());
} finally {
IOUtils.closeQuietly(resp.getEntity().getContent());
}
}
@Test @Test
public void testSearchWithMissingDate2() throws Exception { public void testSearchWithMissingDate2() throws Exception {
MedicationRequest mr1 = new MedicationRequest(); MedicationRequest mr1 = new MedicationRequest();
mr1.getCategory().addCoding().setSystem("urn:medicationroute").setCode("oral"); mr1.getCategory().addCoding().setSystem("urn:medicationroute").setCode("oral");
mr1.addDosageInstruction().getTiming().addEventElement().setValueAsString("2017-01-01"); mr1.addDosageInstruction().getTiming().addEventElement().setValueAsString("2017-01-01");
IIdType id1 = myMedicationRequestDao.create(mr1).getId().toUnqualifiedVersionless(); IIdType id1 = myMedicationRequestDao.create(mr1).getId().toUnqualifiedVersionless();
MedicationRequest mr2 = new MedicationRequest(); MedicationRequest mr2 = new MedicationRequest();
mr2.getCategory().addCoding().setSystem("urn:medicationroute").setCode("oral"); mr2.getCategory().addCoding().setSystem("urn:medicationroute").setCode("oral");
IIdType id2 = myMedicationRequestDao.create(mr2).getId().toUnqualifiedVersionless(); IIdType id2 = myMedicationRequestDao.create(mr2).getId().toUnqualifiedVersionless();
@ -195,38 +222,34 @@ public class ResourceProviderDstu3Test extends BaseResourceProviderDstu3Test {
try { try {
assertEquals(200, resp.getStatusLine().getStatusCode()); assertEquals(200, resp.getStatusLine().getStatusCode());
Bundle bundle = myFhirCtx.newXmlParser().parseResource(Bundle.class, IOUtils.toString(resp.getEntity().getContent(), Constants.CHARSET_UTF8)); Bundle bundle = myFhirCtx.newXmlParser().parseResource(Bundle.class, IOUtils.toString(resp.getEntity().getContent(), Constants.CHARSET_UTF8));
List<String> ids = toUnqualifiedVersionlessIdValues(bundle); List<String> ids = toUnqualifiedVersionlessIdValues(bundle);
assertThat(ids, contains(id1.getValue())); assertThat(ids, contains(id1.getValue()));
} finally { } finally {
IOUtils.closeQuietly(resp); IOUtils.closeQuietly(resp);
} }
} }
@Test @Test
public void testEverythingWithOnlyPatient() { public void testEverythingWithOnlyPatient() {
Patient p = new Patient(); Patient p = new Patient();
p.setActive(true); p.setActive(true);
IIdType id = ourClient.create().resource(p).execute().getId().toUnqualifiedVersionless(); IIdType id = ourClient.create().resource(p).execute().getId().toUnqualifiedVersionless();
myFhirCtx.getRestfulClientFactory().setSocketTimeout(300 * 1000); myFhirCtx.getRestfulClientFactory().setSocketTimeout(300 * 1000);
Bundle response = ourClient Bundle response = ourClient
.operation() .operation()
.onInstance(id) .onInstance(id)
.named("everything") .named("everything")
.withNoParameters(Parameters.class) .withNoParameters(Parameters.class)
.returnResourceType(Bundle.class) .returnResourceType(Bundle.class)
.execute(); .execute();
assertEquals(1, response.getEntry().size()); assertEquals(1, response.getEntry().size());
} }
@Test @Test
public void testSaveAndRetrieveResourceWithExtension() { public void testSaveAndRetrieveResourceWithExtension() {
Patient nextPatient = new Patient(); Patient nextPatient = new Patient();
@ -239,7 +262,7 @@ public class ResourceProviderDstu3Test extends BaseResourceProviderDstu3Test {
ourClient.update().resource(nextPatient).execute(); ourClient.update().resource(nextPatient).execute();
Patient p = ourClient.read().resource(Patient.class).withId("B").execute(); Patient p = ourClient.read().resource(Patient.class).withId("B").execute();
String encoded = myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(p); String encoded = myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(p);
ourLog.info(encoded); ourLog.info(encoded);

View File

@ -24,6 +24,10 @@
looked like before the update. This change was made to support the change above, but looked like before the update. This change was made to support the change above, but
seems like a useful feature all around. seems like a useful feature all around.
</action> </action>
<action type="fix">
Fix HTTP 500 error in JPA server if a numeric search parameter was supplied with no value, e.g.
<![CDATA[<code>GET /Observation?value-quantity=</code>]]>
</action>
</release> </release>
<release version="2.5" date="2017-06-08"> <release version="2.5" date="2017-06-08">
<action type="fix"> <action type="fix">