Skip to content

Commit b999030

Browse files
Update HAPI FHIR R4 to version 8.0.0 (#295)
* Update HAPI FHIR R4 to version `8.0.0` * Update gradle resources to version `8.0.0` * Breaking model changes now means that the `Parameter.getParameter(name)` now returns a `Type` which cannot now be cast to a `StringType`. We can work around this by finding the `ParametersParameterComponent` manually and then casting it to retrieve the value. * Update HAPI FHIR R4 to version `8.0.0` * Due to Parameter changes in the latest version, there is now a slightly different error phrasing in the error returned when a parameter is missing or empty. Integration tests have been updated to reflect this.
1 parent d20c2ea commit b999030

File tree

8 files changed

+64
-36
lines changed

8 files changed

+64
-36
lines changed

build.gradle

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -54,8 +54,8 @@ dependencies {
5454
implementation 'org.apache.httpcomponents:httpclient:4.5.12'
5555
implementation 'com.heroku.sdk:env-keystore:1.1.11'
5656

57-
implementation 'ca.uhn.hapi.fhir:hapi-fhir-base:4.2.0'
58-
implementation 'ca.uhn.hapi.fhir:hapi-fhir-structures-r4:4.2.0'
57+
implementation 'ca.uhn.hapi.fhir:hapi-fhir-base:8.0.0'
58+
implementation 'ca.uhn.hapi.fhir:hapi-fhir-structures-r4:8.0.0'
5959
implementation 'ca.uhn.hapi.fhir:hapi-fhir-validation-resources-r4:8.0.0'
6060
implementation 'com.google.guava:guava:33.4.8-jre'
6161
implementation 'org.apache.qpid:qpid-jms-client:2.7.0'

src/intTest/java/uk/nhs/digital/nhsconnect/nhais/inbound/InboundMeshQueueMultiTransactionTest.java

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,11 @@
11
package uk.nhs.digital.nhsconnect.nhais.inbound;
22

33
import org.assertj.core.api.SoftAssertions;
4+
import org.json.JSONException;
45
import org.junit.jupiter.api.BeforeEach;
56
import org.junit.jupiter.api.Test;
7+
import org.skyscreamer.jsonassert.JSONAssert;
8+
import org.skyscreamer.jsonassert.JSONCompareMode;
69
import org.springframework.beans.factory.annotation.Value;
710
import org.springframework.boot.test.mock.mockito.MockBean;
811
import org.springframework.core.io.Resource;
@@ -100,7 +103,7 @@ void setUp() {
100103
}
101104

102105
@Test
103-
void whenMeshInboundQueueRegistrationMessageIsReceived_thenMessageIsHandled(SoftAssertions softly) throws IOException, JMSException {
106+
void whenMeshInboundQueueRegistrationMessageIsReceived_thenMessageIsHandled(SoftAssertions softly) throws IOException, JMSException, JSONException {
104107
var meshMessage = new MeshMessage()
105108
.setWorkflowId(WorkflowId.REGISTRATION)
106109
.setContent(new String(Files.readAllBytes(interchange.getFile().toPath())));
@@ -148,10 +151,10 @@ private void assertOutboundRecepMessage(SoftAssertions softly) throws IOExceptio
148151
softly.assertThat(meshMessage.getMessageSentTimestamp()).isNull();
149152
}
150153

151-
private void assertGpSystemInboundQueueMessages(SoftAssertions softly) throws JMSException, IOException {
154+
private void assertGpSystemInboundQueueMessages(SoftAssertions softly) throws JMSException, IOException, JSONException {
152155
var gpSystemInboundQueueMessages = IntStream.range(0, 6)
153156
.mapToObj(x -> getGpSystemInboundQueueMessage())
154-
.collect(Collectors.toList());
157+
.toList();
155158

156159
assertGpSystemInboundQueueMessages(
157160
softly, gpSystemInboundQueueMessages.get(0), MESSAGE_1_TRANSACTION_TYPE, TRANSACTION_1_OPERATION_ID, fhirTN1);
@@ -172,7 +175,7 @@ private void assertGpSystemInboundQueueMessages(
172175
Message message,
173176
ReferenceTransactionType.TransactionType expectedTransactionType,
174177
String expectedOperationId,
175-
Resource expectedFhir) throws JMSException, IOException {
178+
Resource expectedFhir) throws JMSException, IOException, JSONException {
176179

177180
// all transactions come from the same interchange and use the same conversation id
178181
String conversationId = message.getStringProperty("ConversationId");
@@ -185,8 +188,12 @@ private void assertGpSystemInboundQueueMessages(
185188
.isEqualTo(expectedOperationId);
186189
softly.assertThat(message.getStringProperty("TransactionType"))
187190
.isEqualTo(expectedTransactionType.name().toLowerCase());
188-
softly.assertThat(parseTextMessage(message))
189-
.isEqualTo(new String(Files.readAllBytes(expectedFhir.getFile().toPath())));
191+
192+
JSONAssert.assertEquals(
193+
parseTextMessage(message),
194+
new String(Files.readAllBytes(expectedFhir.getFile().toPath())),
195+
JSONCompareMode.STRICT
196+
);
190197
}
191198

192199
private void assertInboundStates(SoftAssertions softly, List<InboundState> inboundStates) {

src/intTest/java/uk/nhs/digital/nhsconnect/nhais/inbound/InboundMeshQueueRegistrationTest.java

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,11 @@
11
package uk.nhs.digital.nhsconnect.nhais.inbound;
22

33
import org.assertj.core.api.SoftAssertions;
4+
import org.json.JSONException;
45
import org.junit.jupiter.api.BeforeEach;
56
import org.junit.jupiter.api.Test;
7+
import org.skyscreamer.jsonassert.JSONAssert;
8+
import org.skyscreamer.jsonassert.JSONCompareMode;
69
import org.springframework.beans.factory.annotation.Value;
710
import org.springframework.boot.test.mock.mockito.MockBean;
811
import org.springframework.core.io.Resource;
@@ -63,7 +66,7 @@ void setUp() {
6366
}
6467

6568
@Test
66-
void whenMeshInboundQueueRegistrationMessageIsReceived_thenMessageIsHandled(SoftAssertions softly) throws IOException, JMSException {
69+
void whenMeshInboundQueueRegistrationMessageIsReceived_thenMessageIsHandled(SoftAssertions softly) throws IOException, JMSException, JSONException {
6770
var meshMessage = new MeshMessage()
6871
.setWorkflowId(WorkflowId.REGISTRATION)
6972
.setContent(new String(Files.readAllBytes(interchange.getFile().toPath())))
@@ -86,14 +89,15 @@ private void assertOutboundRecepMessage(SoftAssertions softly) throws IOExceptio
8689
softly.assertThat(meshMessage.getMessageSentTimestamp()).isNull();
8790
}
8891

89-
private void assertGpSystemInboundQueueMessage(SoftAssertions softly) throws JMSException, IOException {
92+
private void assertGpSystemInboundQueueMessage(SoftAssertions softly) throws JMSException, IOException, JSONException {
9093
var message = getGpSystemInboundQueueMessage();
9194
var content = parseTextMessage(message);
9295
var expectedContent = new String(Files.readAllBytes(fhir.getFile().toPath()));
9396

9497
softly.assertThat(message.getStringProperty("OperationId")).isEqualTo(OPERATION_ID);
9598
softly.assertThat(message.getStringProperty("TransactionType")).isEqualTo(TRANSACTION_TYPE.name().toLowerCase());
96-
softly.assertThat(content).isEqualTo(expectedContent);
99+
100+
JSONAssert.assertEquals(expectedContent, content, JSONCompareMode.STRICT);
97101
}
98102

99103
private void assertInboundState(SoftAssertions softly) {

src/intTest/java/uk/nhs/digital/nhsconnect/nhais/inbound/InboundUserAcceptanceTest.java

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,13 @@
11
package uk.nhs.digital.nhsconnect.nhais.inbound;
22

3+
import org.json.JSONException;
34
import org.junit.jupiter.api.AfterEach;
45
import org.junit.jupiter.api.BeforeEach;
56
import org.junit.jupiter.api.extension.ExtendWith;
67
import org.junit.jupiter.params.ParameterizedTest;
78
import org.junit.jupiter.params.provider.ArgumentsSource;
9+
import org.skyscreamer.jsonassert.JSONAssert;
10+
import org.skyscreamer.jsonassert.JSONCompareMode;
811
import org.springframework.beans.factory.annotation.Autowired;
912
import org.springframework.test.annotation.DirtiesContext;
1013
import uk.nhs.digital.nhsconnect.nhais.IntegrationBaseTest;
@@ -20,6 +23,7 @@
2023

2124
import jakarta.jms.JMSException;
2225
import jakarta.jms.Message;
26+
2327
import java.util.List;
2428
import java.util.stream.Collectors;
2529

@@ -99,17 +103,17 @@ private void verifyThatCloseQuarterNotificationIsNotPresentOnGpSystemInboundQueu
99103
assertThat(gpSystemInboundQueueMessage).isNull();
100104
}
101105

102-
private void verifyThatNonCloseQuarterNotificationMessageIsTranslated(TestData testData, Message gpSystemInboundQueueMessage) throws JMSException {
106+
private void verifyThatNonCloseQuarterNotificationMessageIsTranslated(TestData testData, Message gpSystemInboundQueueMessage) throws JMSException, JSONException {
103107
assertThat(gpSystemInboundQueueMessage).isNotNull();
104108
// assert transaction type in JMS header is correct
105109
assertMessageHeaders(gpSystemInboundQueueMessage, "fp69_prior_notification");
106110
// assert output body is correct
107111
assertMessageBody(gpSystemInboundQueueMessage, testData.getJson());
108112
}
109113

110-
private void assertMessageBody(Message gpSystemInboundQueueMessage, String expectedBody) throws JMSException {
114+
private void assertMessageBody(Message gpSystemInboundQueueMessage, String expectedBody) throws JMSException, JSONException {
111115
var body = parseTextMessage(gpSystemInboundQueueMessage);
112-
assertThat(body).isEqualTo(expectedBody);
116+
JSONAssert.assertEquals(expectedBody, body, JSONCompareMode.STRICT);
113117
}
114118

115119
private void assertMessageHeaders(Message gpSystemInboundQueueMessage, String expectedTransactionType) throws JMSException {

src/intTest/java/uk/nhs/digital/nhsconnect/nhais/outbound/controller/DeductionIntegrationTest.java

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,12 @@
3131
@DirtiesContext
3232
public class DeductionIntegrationTest {
3333
public static final String URL = "/fhir/Patient/$nhais.deduction";
34+
private static final String ATTRIBUTE_VALUE_MUST_NOT_BE_EMPTY =
35+
"Invalid attribute value \"\": Attribute value must not be empty (\"\")";
36+
private static final String INVALID_VALUE_STRING_PARAMETER =
37+
"Unable to parse JSON resource as a Parameters: HAPI-1821: [element=\"valueString\"] ";
38+
private static final String INVALID_VALUE_PARAMETER =
39+
"Unable to parse JSON resource as a Parameters: HAPI-1821: [element=\"value\"] ";
3440

3541
@Autowired
3642
private MockMvc mockMvc;
@@ -91,7 +97,8 @@ void whenEmptyNhsNumber_thenRespond400() throws Exception {
9197
.andExpect(status().isBadRequest())
9298
.andReturn();
9399
OperationOutcome operationOutcome = (OperationOutcome) fhirParser.parse(result.getResponse().getContentAsString());
94-
assertThat(operationOutcome.getIssueFirstRep().getDetails().getText()).contains("Unable to parse JSON resource as a Parameters: Invalid attribute value \"\": Attribute values must not be empty (\"\")");
100+
assertThat(operationOutcome.getIssueFirstRep().getDetails().getText())
101+
.contains(INVALID_VALUE_PARAMETER + ATTRIBUTE_VALUE_MUST_NOT_BE_EMPTY);
95102
}
96103

97104
@Test
@@ -131,7 +138,8 @@ void whenEmptyDateOfDeduction_thenRespond400() throws Exception {
131138
.andExpect(status().isBadRequest())
132139
.andReturn();
133140
OperationOutcome operationOutcome = (OperationOutcome) fhirParser.parse(result.getResponse().getContentAsString());
134-
assertThat(operationOutcome.getIssueFirstRep().getDetails().getText()).contains("Unable to parse JSON resource as a Parameters: Invalid attribute value \"\": Attribute values must not be empty (\"\")");
141+
assertThat(operationOutcome.getIssueFirstRep().getDetails().getText())
142+
.contains(INVALID_VALUE_STRING_PARAMETER + ATTRIBUTE_VALUE_MUST_NOT_BE_EMPTY);
135143
}
136144

137145
@Test
@@ -171,7 +179,8 @@ void whenEmptyReasonForDeduction_thenRespond400() throws Exception {
171179
.andExpect(status().isBadRequest())
172180
.andReturn();
173181
OperationOutcome operationOutcome = (OperationOutcome) fhirParser.parse(result.getResponse().getContentAsString());
174-
assertThat(operationOutcome.getIssueFirstRep().getDetails().getText()).contains("Unable to parse JSON resource as a Parameters: Invalid attribute value \"\": Attribute values must not be empty (\"\")");
182+
assertThat(operationOutcome.getIssueFirstRep().getDetails().getText())
183+
.contains(INVALID_VALUE_STRING_PARAMETER + ATTRIBUTE_VALUE_MUST_NOT_BE_EMPTY);
175184
}
176185

177186
@Test
@@ -194,4 +203,4 @@ void whenNullReasonForDeduction_thenRespond400() throws Exception {
194203
assertThat(operationOutcome.getIssueFirstRep().getDetails().getText()).contains(ParameterNames.DEDUCTION_REASON_CODE);
195204
}
196205

197-
}
206+
}

src/intTest/java/uk/nhs/digital/nhsconnect/nhais/outbound/controller/FhirControllerIntegrationTest.java

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,12 @@
2525
@AutoConfigureMockMvc
2626
@Slf4j
2727
public class FhirControllerIntegrationTest {
28+
private static final String INVALID_VALUE_STRING_PARAMETER =
29+
"Unable to parse JSON resource as a Parameters: HAPI-1821: [element=\"valueString\"] ";
30+
private static final String INVALID_VALUE_PARAMETER =
31+
"Unable to parse JSON resource as a Parameters: HAPI-1821: [element=\"value\"] ";
32+
private static final String ATTRIBUTE_VALUE_MUST_NOT_BE_EMPTY =
33+
"Invalid attribute value \"\": Attribute value must not be empty (\"\")";
2834

2935
@Autowired
3036
private MockMvc mockMvc;
@@ -80,7 +86,7 @@ void whenDeductionNoDestinationHaCipher_thenRerturns400() throws Exception {
8086
.andReturn();
8187
OperationOutcome operationOutcome = (OperationOutcome) fhirParser.parse(result.getResponse().getContentAsString());
8288
assertThat(operationOutcome.getIssueFirstRep().getDetails().getText())
83-
.contains("Invalid attribute value \"\": Attribute values must not be empty");
89+
.contains(INVALID_VALUE_PARAMETER + ATTRIBUTE_VALUE_MUST_NOT_BE_EMPTY);
8490
}
8591

8692
@Test
@@ -91,7 +97,7 @@ void whenRemovalNoDestinationHaCipher_thenRerturns400() throws Exception {
9197
.andReturn();
9298
OperationOutcome operationOutcome = (OperationOutcome) fhirParser.parse(result.getResponse().getContentAsString());
9399
assertThat(operationOutcome.getIssueFirstRep().getDetails().getText())
94-
.contains("Invalid attribute value \"\": Attribute values must not be empty");
100+
.contains(INVALID_VALUE_PARAMETER + ATTRIBUTE_VALUE_MUST_NOT_BE_EMPTY);
95101
}
96102

97103

@@ -103,7 +109,7 @@ void whenDeductionNoGpCode_thenReturns400() throws Exception {
103109
.andReturn();
104110
OperationOutcome operationOutcome = (OperationOutcome) fhirParser.parse(result.getResponse().getContentAsString());
105111
assertThat(operationOutcome.getIssueFirstRep().getDetails().getText())
106-
.contains("Invalid attribute value \"\": Attribute values must not be empty");
112+
.contains(INVALID_VALUE_PARAMETER + ATTRIBUTE_VALUE_MUST_NOT_BE_EMPTY);
107113
}
108114

109115
@Test
@@ -114,7 +120,7 @@ void whenRemovalNoGpCode_thenReturns400() throws Exception {
114120
.andReturn();
115121
OperationOutcome operationOutcome = (OperationOutcome) fhirParser.parse(result.getResponse().getContentAsString());
116122
assertThat(operationOutcome.getIssueFirstRep().getDetails().getText())
117-
.contains("Invalid attribute value \"\": Attribute values must not be empty");
123+
.contains(INVALID_VALUE_PARAMETER + ATTRIBUTE_VALUE_MUST_NOT_BE_EMPTY);
118124
}
119125

120126
@Test
@@ -125,7 +131,7 @@ void whenDeductionNpGpTradingPartnerCode_thenReturns400() throws Exception {
125131
.andReturn();
126132
OperationOutcome operationOutcome = (OperationOutcome) fhirParser.parse(result.getResponse().getContentAsString());
127133
assertThat(operationOutcome.getIssueFirstRep().getDetails().getText())
128-
.contains("Invalid attribute value \"\": Attribute values must not be empty");
134+
.contains(INVALID_VALUE_STRING_PARAMETER + ATTRIBUTE_VALUE_MUST_NOT_BE_EMPTY);
129135
}
130136

131137
@Test
@@ -136,7 +142,7 @@ void whenRemovalNpGpTradingPartnerCode_thenReturns400() throws Exception {
136142
.andReturn();
137143
OperationOutcome operationOutcome = (OperationOutcome) fhirParser.parse(result.getResponse().getContentAsString());
138144
assertThat(operationOutcome.getIssueFirstRep().getDetails().getText())
139-
.contains("Invalid attribute value \"\": Attribute values must not be empty");
145+
.contains(INVALID_VALUE_STRING_PARAMETER + ATTRIBUTE_VALUE_MUST_NOT_BE_EMPTY);
140146
}
141147

142148
@Test

src/intTest/java/uk/nhs/digital/nhsconnect/nhais/outbound/controller/RemovalIntegrationTest.java

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,11 @@ void whenEmptyNhsNumber_thenRespond400() throws Exception {
8989
.andExpect(status().isBadRequest())
9090
.andReturn();
9191
OperationOutcome operationOutcome = (OperationOutcome) fhirParser.parse(result.getResponse().getContentAsString());
92-
assertThat(operationOutcome.getIssueFirstRep().getDetails().getText()).contains("Unable to parse JSON resource as a Parameters: Invalid attribute value \"\": Attribute values must not be empty (\"\")");
92+
assertThat(operationOutcome.getIssueFirstRep().getDetails().getText())
93+
.contains(
94+
"Unable to parse JSON resource as a Parameters: HAPI-1821: [element=\"value\"] "
95+
+ "Invalid attribute value \"\": Attribute value must not be empty (\"\")"
96+
);
9397
}
9498

9599

src/main/java/uk/nhs/digital/nhsconnect/nhais/model/fhir/ParametersExtension.java

Lines changed: 5 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
package uk.nhs.digital.nhsconnect.nhais.model.fhir;
22

33
import lombok.RequiredArgsConstructor;
4-
import lombok.SneakyThrows;
54
import org.apache.commons.lang3.StringUtils;
65
import org.hl7.fhir.r4.model.Extension;
76
import org.hl7.fhir.r4.model.Parameters;
@@ -14,7 +13,6 @@
1413

1514
import java.util.Objects;
1615
import java.util.Optional;
17-
import java.util.function.Supplier;
1816

1917
@RequiredArgsConstructor
2018
public class ParametersExtension {
@@ -79,19 +77,15 @@ public static Optional<String> extractOptionalValue(Parameters parameters, Strin
7977
}
8078

8179
public Optional<String> extractOptionalValue(String name) {
82-
return Optional.ofNullable(parameters.getParameter(name))
80+
return parameters.getParameter()
81+
.stream()
82+
.filter(p -> p.getName().equals(name))
83+
.findFirst()
84+
.map(Parameters.ParametersParameterComponent::getValue)
8385
.map(StringType.class::cast)
8486
.map(StringType::getValueAsString);
8587
}
8688

87-
@SneakyThrows
88-
public String extractValueOrThrow(String name, Supplier<? extends Throwable> exception) {
89-
return Optional.ofNullable(parameters.getParameter(name))
90-
.map(StringType.class::cast)
91-
.map(StringType::getValueAsString)
92-
.orElseThrow(exception);
93-
}
94-
9589
public int size() {
9690
return parameters.getParameter().size();
9791
}

0 commit comments

Comments
 (0)