From f2627959c2d19c7e324ecacb1d92c0320c8b676f Mon Sep 17 00:00:00 2001 From: ianmarshall Date: Mon, 24 May 2021 22:09:44 -0400 Subject: [PATCH 1/4] Add null check on code lookup result. --- ...rminologyDisplayPopulationInterceptor.java | 2 +- ...ologyDisplayPopulationInterceptorTest.java | 50 +++++++++++++++++++ 2 files changed, 51 insertions(+), 1 deletion(-) diff --git a/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/interceptor/ResponseTerminologyDisplayPopulationInterceptor.java b/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/interceptor/ResponseTerminologyDisplayPopulationInterceptor.java index bcc22a8cb82..7082f28e78f 100644 --- a/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/interceptor/ResponseTerminologyDisplayPopulationInterceptor.java +++ b/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/interceptor/ResponseTerminologyDisplayPopulationInterceptor.java @@ -104,7 +104,7 @@ public class ResponseTerminologyDisplayPopulationInterceptor extends BaseRespons if (myValidationSupport.isCodeSystemSupported(validationSupportContext, system)) { IValidationSupport.LookupCodeResult lookupCodeResult = myValidationSupport.lookupCode(validationSupportContext, system, code); - if (lookupCodeResult.isFound()) { + if (lookupCodeResult != null && lookupCodeResult.isFound()) { String newDisplay = lookupCodeResult.getCodeDisplay(); IPrimitiveType newString = myStringDefinition.newInstance(newDisplay); myCodingDisplayChild.getMutator().addValue(theElement, newString); diff --git a/hapi-fhir-validation/src/test/java/ca/uhn/fhir/rest/server/interceptor/ResponseTerminologyDisplayPopulationInterceptorTest.java b/hapi-fhir-validation/src/test/java/ca/uhn/fhir/rest/server/interceptor/ResponseTerminologyDisplayPopulationInterceptorTest.java index 1a07ac3875e..52000ffacb6 100644 --- a/hapi-fhir-validation/src/test/java/ca/uhn/fhir/rest/server/interceptor/ResponseTerminologyDisplayPopulationInterceptorTest.java +++ b/hapi-fhir-validation/src/test/java/ca/uhn/fhir/rest/server/interceptor/ResponseTerminologyDisplayPopulationInterceptorTest.java @@ -2,6 +2,8 @@ package ca.uhn.fhir.rest.server.interceptor; import ca.uhn.fhir.context.FhirContext; import ca.uhn.fhir.context.FhirVersionEnum; +import ca.uhn.fhir.context.support.IValidationSupport; +import ca.uhn.fhir.context.support.ValidationSupportContext; import ca.uhn.fhir.rest.client.api.IGenericClient; import ca.uhn.fhir.test.utilities.server.HashMapResourceProviderExtension; import ca.uhn.fhir.test.utilities.server.RestfulServerExtension; @@ -15,6 +17,7 @@ import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.RegisterExtension; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNull; public class ResponseTerminologyDisplayPopulationInterceptorTest { @@ -50,6 +53,19 @@ public class ResponseTerminologyDisplayPopulationInterceptorTest { assertEquals("Annulled", p.getMaritalStatus().getCoding().get(0).getDisplay()); } + @Test + public void testPopulateCoding_Read_NullableValidationSupport() { + myServerExtension.getRestfulServer().registerInterceptor(new ResponseTerminologyDisplayPopulationInterceptor(new NullableValidationSupport(myCtx))); + + Patient p = new Patient(); + p.getMaritalStatus().addCoding().setSystem("http://terminology.hl7.org/CodeSystem/v3-MaritalStatus").setCode("A"); + IIdType id = myClient.create().resource(p).execute().getId(); + + p = myClient.read().resource(Patient.class).withId(id).execute(); + assertEquals(1, p.getMaritalStatus().getCoding().size()); + assertNull(p.getMaritalStatus().getCoding().get(0).getDisplay()); + } + @Test public void testPopulateCoding_Search() { myServerExtension.getRestfulServer().registerInterceptor(new ResponseTerminologyDisplayPopulationInterceptor(myCtx.getValidationSupport())); @@ -65,6 +81,21 @@ public class ResponseTerminologyDisplayPopulationInterceptorTest { assertEquals("Annulled", p.getMaritalStatus().getCoding().get(0).getDisplay()); } + @Test + public void testPopulateCoding_Search_NullableValidationSupport() { + myServerExtension.getRestfulServer().registerInterceptor(new ResponseTerminologyDisplayPopulationInterceptor(new NullableValidationSupport(myCtx))); + + Patient p = new Patient(); + p.getMaritalStatus().addCoding().setSystem("http://terminology.hl7.org/CodeSystem/v3-MaritalStatus").setCode("A"); + IIdType id = myClient.create().resource(p).execute().getId(); + + Bundle bundle = myClient.search().forResource(Patient.class).returnBundle(Bundle.class).execute(); + assertEquals(1, bundle.getEntry().size()); + p = (Patient) bundle.getEntry().get(0).getResource(); + assertEquals(1, p.getMaritalStatus().getCoding().size()); + assertNull(p.getMaritalStatus().getCoding().get(0).getDisplay()); + } + @Test public void testDontPopulateCodingIfAlreadyPopulated() { myServerExtension.getRestfulServer().registerInterceptor(new ResponseTerminologyDisplayPopulationInterceptor(myCtx.getValidationSupport())); @@ -91,4 +122,23 @@ public class ResponseTerminologyDisplayPopulationInterceptorTest { assertEquals(null, p.getMaritalStatus().getCoding().get(0).getDisplay()); } + private static class NullableValidationSupport implements IValidationSupport { + + private static FhirContext myStaticCtx; + + NullableValidationSupport(FhirContext theCtx) { + myStaticCtx = theCtx; + } + + @Override + public FhirContext getFhirContext() { + return myStaticCtx; + } + + @Override + public boolean isCodeSystemSupported(ValidationSupportContext theValidationSupportContext, String theSystem) { + return true; + } + } + } From 1b387a574025330afc4d0faed0365b903e592ef6 Mon Sep 17 00:00:00 2001 From: ianmarshall Date: Mon, 24 May 2021 22:14:02 -0400 Subject: [PATCH 2/4] Add null check on code lookup result. --- .../2674-fix-npe-on-display-population-interceptor.yaml | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/5_5_0/2674-fix-npe-on-display-population-interceptor.yaml diff --git a/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/5_5_0/2674-fix-npe-on-display-population-interceptor.yaml b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/5_5_0/2674-fix-npe-on-display-population-interceptor.yaml new file mode 100644 index 00000000000..800c6ab48d7 --- /dev/null +++ b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/5_5_0/2674-fix-npe-on-display-population-interceptor.yaml @@ -0,0 +1,5 @@ +--- +type: fix +issue: 2674 +title: "A null-pointer exception was fixed when a ResponseTerminologyDisplayInterceptor is registered and a search + or read response returns a resource with code value that in turn returns a null code lookup." From 8e552916ee5bb297194185d0c076a477f689f3b9 Mon Sep 17 00:00:00 2001 From: ianmarshall Date: Tue, 25 May 2021 09:07:28 -0400 Subject: [PATCH 3/4] Add null check on code lookup result. --- ...ologyDisplayPopulationInterceptorTest.java | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/hapi-fhir-validation/src/test/java/ca/uhn/fhir/rest/server/interceptor/ResponseTerminologyDisplayPopulationInterceptorTest.java b/hapi-fhir-validation/src/test/java/ca/uhn/fhir/rest/server/interceptor/ResponseTerminologyDisplayPopulationInterceptorTest.java index 52000ffacb6..2dd9ce074a0 100644 --- a/hapi-fhir-validation/src/test/java/ca/uhn/fhir/rest/server/interceptor/ResponseTerminologyDisplayPopulationInterceptorTest.java +++ b/hapi-fhir-validation/src/test/java/ca/uhn/fhir/rest/server/interceptor/ResponseTerminologyDisplayPopulationInterceptorTest.java @@ -54,7 +54,7 @@ public class ResponseTerminologyDisplayPopulationInterceptorTest { } @Test - public void testPopulateCoding_Read_NullableValidationSupport() { + public void testDontPopulateCodingIfLookupReturnsNull_Read() { myServerExtension.getRestfulServer().registerInterceptor(new ResponseTerminologyDisplayPopulationInterceptor(new NullableValidationSupport(myCtx))); Patient p = new Patient(); @@ -72,7 +72,7 @@ public class ResponseTerminologyDisplayPopulationInterceptorTest { Patient p = new Patient(); p.getMaritalStatus().addCoding().setSystem("http://terminology.hl7.org/CodeSystem/v3-MaritalStatus").setCode("A"); - IIdType id = myClient.create().resource(p).execute().getId(); + myClient.create().resource(p).execute(); Bundle bundle = myClient.search().forResource(Patient.class).returnBundle(Bundle.class).execute(); assertEquals(1, bundle.getEntry().size()); @@ -82,12 +82,12 @@ public class ResponseTerminologyDisplayPopulationInterceptorTest { } @Test - public void testPopulateCoding_Search_NullableValidationSupport() { + public void testDontPopulateCodingIfLookupReturnsNull_Search() { myServerExtension.getRestfulServer().registerInterceptor(new ResponseTerminologyDisplayPopulationInterceptor(new NullableValidationSupport(myCtx))); Patient p = new Patient(); - p.getMaritalStatus().addCoding().setSystem("http://terminology.hl7.org/CodeSystem/v3-MaritalStatus").setCode("A"); - IIdType id = myClient.create().resource(p).execute().getId(); + p.getMaritalStatus().addCoding().setSystem("http://terminology.hl7.org/CodeSystem/v3-MaritalStatus").setCode("zz"); + myClient.create().resource(p).execute(); Bundle bundle = myClient.search().forResource(Patient.class).returnBundle(Bundle.class).execute(); assertEquals(1, bundle.getEntry().size()); @@ -101,7 +101,7 @@ public class ResponseTerminologyDisplayPopulationInterceptorTest { myServerExtension.getRestfulServer().registerInterceptor(new ResponseTerminologyDisplayPopulationInterceptor(myCtx.getValidationSupport())); Patient p = new Patient(); - p.getMaritalStatus().addCoding().setSystem("http://terminology.hl7.org/CodeSystem/v3-MaritalStatus").setCode("A").setDisplay("FOO"); + p.getMaritalStatus().addCoding().setSystem("http://terminology.hl7.org/CodeSystem/v3-MaritalStatus").setCode("zz").setDisplay("FOO"); IIdType id = myClient.create().resource(p).execute().getId(); p = myClient.read().resource(Patient.class).withId(id).execute(); @@ -119,7 +119,7 @@ public class ResponseTerminologyDisplayPopulationInterceptorTest { p = myClient.read().resource(Patient.class).withId(id).execute(); assertEquals(1, p.getMaritalStatus().getCoding().size()); - assertEquals(null, p.getMaritalStatus().getCoding().get(0).getDisplay()); + assertNull(p.getMaritalStatus().getCoding().get(0).getDisplay()); } private static class NullableValidationSupport implements IValidationSupport { @@ -139,6 +139,11 @@ public class ResponseTerminologyDisplayPopulationInterceptorTest { public boolean isCodeSystemSupported(ValidationSupportContext theValidationSupportContext, String theSystem) { return true; } + + @Override + public LookupCodeResult lookupCode(ValidationSupportContext theValidationSupportContext, String theSystem, String theCode) { + return null; + } } } From a878ef24961de18bb7b07116e0c895399de4e6a6 Mon Sep 17 00:00:00 2001 From: ianmarshall Date: Tue, 25 May 2021 09:09:41 -0400 Subject: [PATCH 4/4] Add null check on code lookup result. --- .../ResponseTerminologyDisplayPopulationInterceptorTest.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/hapi-fhir-validation/src/test/java/ca/uhn/fhir/rest/server/interceptor/ResponseTerminologyDisplayPopulationInterceptorTest.java b/hapi-fhir-validation/src/test/java/ca/uhn/fhir/rest/server/interceptor/ResponseTerminologyDisplayPopulationInterceptorTest.java index 2dd9ce074a0..f7e58a17002 100644 --- a/hapi-fhir-validation/src/test/java/ca/uhn/fhir/rest/server/interceptor/ResponseTerminologyDisplayPopulationInterceptorTest.java +++ b/hapi-fhir-validation/src/test/java/ca/uhn/fhir/rest/server/interceptor/ResponseTerminologyDisplayPopulationInterceptorTest.java @@ -58,7 +58,7 @@ public class ResponseTerminologyDisplayPopulationInterceptorTest { myServerExtension.getRestfulServer().registerInterceptor(new ResponseTerminologyDisplayPopulationInterceptor(new NullableValidationSupport(myCtx))); Patient p = new Patient(); - p.getMaritalStatus().addCoding().setSystem("http://terminology.hl7.org/CodeSystem/v3-MaritalStatus").setCode("A"); + p.getMaritalStatus().addCoding().setSystem("http://terminology.hl7.org/CodeSystem/v3-MaritalStatus").setCode("zz"); IIdType id = myClient.create().resource(p).execute().getId(); p = myClient.read().resource(Patient.class).withId(id).execute(); @@ -101,7 +101,7 @@ public class ResponseTerminologyDisplayPopulationInterceptorTest { myServerExtension.getRestfulServer().registerInterceptor(new ResponseTerminologyDisplayPopulationInterceptor(myCtx.getValidationSupport())); Patient p = new Patient(); - p.getMaritalStatus().addCoding().setSystem("http://terminology.hl7.org/CodeSystem/v3-MaritalStatus").setCode("zz").setDisplay("FOO"); + p.getMaritalStatus().addCoding().setSystem("http://terminology.hl7.org/CodeSystem/v3-MaritalStatus").setCode("A").setDisplay("FOO"); IIdType id = myClient.create().resource(p).execute().getId(); p = myClient.read().resource(Patient.class).withId(id).execute();