hapifhir / hapi-fhir

🔥 HAPI FHIR - Java API for HL7 FHIR Clients and Servers
http://hapifhir.io
Apache License 2.0
2.03k stars 1.33k forks source link

NPE Occurs When Issuing DSTU3 PUT ProcedureRequest Where occurrenceTiming.repeat.boundsPeriod.end Is Not Provided #2569

Closed KevinDougan closed 3 years ago

KevinDougan commented 3 years ago

Problem Description When issuing a PUT of a DSTU3 ProcedureRequest resource where occurrenceTiming.repeat.boundsPeriod.start is provided but occurrenceTiming.repeat.boundsPeriod.end is not provided, the system responds with a NullPointerException during an attempted parsing of the non-existent occurrenceTiming.repeat.boundsPeriod.end property.

Here is an example of a PUT operation that exposes the NPE with the sample JSON file provided in the next Comment below: curl -X PUT -H "Content-Type: application/json" --data @ProcedureRequest.json "http://127.0.0.1:8000/ProcedureRequest/A1"

To Reproduce Issue a PUT using the example ProcedureRequest Resource (see next Comment below) to a DSTU3 Server.

Expected Behaviour The Server should create the ProcedureRequest resource with the provided occurrenceTiming.repeat.boundsPeriod.start value and no value for the occurrenceTiming.repeat.boundsPeriod.end property. Note from the specification that the Period.end property is not required: http://hl7.org/fhir/stu3/datatypes.html#Period

Observed Behaviour The Server responds with a NullPointerException during processing.

{
  "resourceType": "OperationOutcome",
  "issue": [ {
    "severity": "error",
    "code": "processing",
    "diagnostics": "Failed to call access method: java.lang.NullPointerException"
  } ]
}
KevinDougan commented 3 years ago
{
    "resourceType":"ProcedureRequest",
    "id":"A1",
    "identifier":[
       {
          "system":"urn:oid:2.16.840.1.113883.3.1",
          "value":"A1"
       }
    ],
    "occurrenceTiming":{
       "repeat":{
          "boundsPeriod":{
             "start":"2021-01-31T00:00:00.000-05:00"
          },
          "count": 1,
          "frequency": 1,
          "period": 1.0,
          "periodUnit": "mo",
          "dayOfWeek": [
             "sun"
          ]
       },
       "code":{
          "coding":[
             {
                "system":"http://fhir.org/fhir/OrderSchedule",
                "code":"Once a month",
                "display":"Once a month"
             }
          ]
       }
    }
 }
KevinDougan commented 3 years ago

Here's a sample Stack Trace of the NPE:

Caused by: java.lang.NullPointerException: null
    at java.base/java.util.TreeMap.put(TreeMap.java:561)
    at java.base/java.util.TreeSet.add(TreeSet.java:255)
    at ca.uhn.fhir.jpa.searchparam.extractor.BaseSearchParamExtractor$DateExtractor.addDate_Timing(BaseSearchParamExtractor.java:1368)
    at ca.uhn.fhir.jpa.searchparam.extractor.BaseSearchParamExtractor$DateExtractor.extract(BaseSearchParamExtractor.java:1309)
    at ca.uhn.fhir.jpa.searchparam.extractor.BaseSearchParamExtractor.extractSearchParam(BaseSearchParamExtractor.java:964)
    at ca.uhn.fhir.jpa.searchparam.extractor.BaseSearchParamExtractor.extractSearchParams(BaseSearchParamExtractor.java:946)
    at ca.uhn.fhir.jpa.searchparam.extractor.BaseSearchParamExtractor.extractSearchParamDates(BaseSearchParamExtractor.java:339)
    at ca.uhn.fhir.jpa.searchparam.extractor.SearchParamExtractorService.extractSearchParamDates(SearchParamExtractorService.java:382)
    at ca.uhn.fhir.jpa.searchparam.extractor.SearchParamExtractorService.extractSearchIndexParameters(SearchParamExtractorService.java:131)
    at ca.uhn.fhir.jpa.searchparam.extractor.SearchParamExtractorService.extractFromResource(SearchParamExtractorService.java:99)
    at ca.uhn.fhir.jpa.dao.index.SearchParamWithInlineReferencesExtractor.populateFromResource(SearchParamWithInlineReferencesExtractor.java:108)
    at ca.uhn.fhir.jpa.dao.BaseHapiFhirDao.updateEntity(BaseHapiFhirDao.java:1048)
    at ca.uhn.fhir.jpa.dao.BaseHapiFhirResourceDao.doCreateForPostOrPut(BaseHapiFhirResourceDao.java:325)
    at ca.uhn.fhir.jpa.dao.BaseHapiFhirResourceDao.doUpdate(BaseHapiFhirResourceDao.java:1502)
    at ca.uhn.fhir.jpa.dao.BaseHapiFhirResourceDao.lambda$update$12(BaseHapiFhirResourceDao.java:1461)
    at ca.uhn.fhir.jpa.dao.tx.HapiTransactionService.execute(HapiTransactionService.java:65) [1 skipped]
    at ca.uhn.fhir.jpa.dao.BaseHapiFhirResourceDao.update(BaseHapiFhirResourceDao.java:1461)
    at ca.uhn.fhir.jpa.dao.BaseHapiFhirResourceDao.update(BaseHapiFhirResourceDao.java:1441)
    at ca.uhn.fhir.jpa.dao.BaseHapiFhirResourceDao.update(BaseHapiFhirResourceDao.java:1436)
    at ca.uhn.fhir.jpa.dao.BaseHapiFhirResourceDao.update(BaseHapiFhirResourceDao.java:1426)
KevinDougan commented 3 years ago

This was fixed on Feb. 24, 2021 wth the following Pull Request: https://github.com/hapifhir/hapi-fhir/pull/2417

mimccu commented 3 years ago

Hi @KevinDougan-SmileCDR and @jamesagnew,

I see this issue was fixed and checked into the master branch when I pull from https://github.com/hapifhir/hapi-fhir.git. I am looking at the following code from master: BaseSearchParamExtractor.txt This was taken from the following folder structure: hapi-fhir\hapi-fhir-jpaserver-searchparam\src\main\java\ca\uhn\fhir\jpa\searchparam\extractor

For the private addDate_Timing method on line 1375, I see null checks added on lines 1399 and 1402. This method is under private class DateExtractor implements IExtractor. However, there are two addDate_Timing methods in this file. The other is a method of BaseSearchParamExtractor.java at the "top level" and not under a private class. This method starts on line 774 but does not have any null checks on lines 800 and 801. Does this method need null checks as well? I'm not sure when this method would be called verses the addDate_Timing method under the sub-classed DateExtractor. The stack trace provided by Kevin Dougan points to the method under the private class.

We recently ran into this issue on an older version of HAPI (version 4.2.0) and it does not appear to be using the method under the private class. Stack trace is below:

Caused by: java.lang.NullPointerException: null at java.base/java.util.TreeMap.put(TreeMap.java:561) at java.base/java.util.TreeSet.add(TreeSet.java:255) at ca.uhn.fhir.jpa.searchparam.extractor.BaseSearchParamExtractor.addDate_Timing(BaseSearchParamExtractor.java:638) at ca.uhn.fhir.jpa.searchparam.extractor.BaseSearchParamExtractor.lambda$extractSearchParamDates$4(BaseSearchParamExtractor.java:338) at ca.uhn.fhir.jpa.searchparam.extractor.BaseSearchParamExtractor.extractSearchParams(BaseSearchParamExtractor.java:807) at ca.uhn.fhir.jpa.searchparam.extractor.BaseSearchParamExtractor.extractSearchParamDates(BaseSearchParamExtractor.java:349) at ca.uhn.fhir.jpa.searchparam.extractor.SearchParamExtractorService.extractSearchParamDates(SearchParamExtractorService.java:121) at ca.uhn.fhir.jpa.searchparam.extractor.SearchParamExtractorService.extractFromResource(SearchParamExtractorService.java:62) at ca.uhn.fhir.jpa.dao.index.SearchParamWithInlineReferencesExtractor.populateFromResource(SearchParamWithInlineReferencesExtractor.java:99) at ca.uhn.fhir.jpa.dao.BaseHapiFhirDao.updateEntity(BaseHapiFhirDao.java:980)

NOTE: We tested the same Bundle (that caused the NPE above) against a newer version of HAPI (HAPI FHIR 5.4.1 REST Server (FHIR Server; FHIR 4.0.1/R4)) and it did not cause a NPE.

Thanks, Mike