Fixed R5 Subscription deserialization (#4922)

* review feedback

* fixed

* changelog

* test both ways

* add bundle test

* change how toplevel is detected since in some contexts the parent state can be a non-null pre-resource state

* fix v2 issues

---------

Co-authored-by: Ken Stevens <ken@smilecdr.com>
This commit is contained in:
Ken Stevens 2023-05-19 20:32:25 -04:00 committed by GitHub
parent a722cc46a9
commit d932730525
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 106 additions and 1 deletions

View File

@ -1003,7 +1003,9 @@ public class JsonParser extends BaseParser implements IJsonLikeParser {
for (Iterator<String> keyIter = theObject.keyIterator(); keyIter.hasNext(); ) { for (Iterator<String> keyIter = theObject.keyIterator(); keyIter.hasNext(); ) {
String nextName = keyIter.next(); String nextName = keyIter.next();
if ("resourceType".equals(nextName)) { if ("resourceType".equals(nextName)) {
continue; if (theState.isToplevelResourceElement()) {
continue;
}
} else if ("extension".equals(nextName)) { } else if ("extension".equals(nextName)) {
BaseJsonLikeArray array = grabJsonArray(theObject, nextName, "extension"); BaseJsonLikeArray array = grabJsonArray(theObject, nextName, "extension");
parseExtension(theState, array, false); parseExtension(theState, array, false);

View File

@ -148,6 +148,10 @@ class ParserState<T> {
return myState.isPreResource(); return myState.isPreResource();
} }
boolean isToplevelResourceElement() {
return myState instanceof ParserState.ResourceStateHl7Org || myState instanceof ParserState.ResourceStateHapi;
}
private Object newContainedDt(IResource theTarget) { private Object newContainedDt(IResource theTarget) {
return ReflectionUtil.newInstance(theTarget.getStructureFhirVersionEnum().getVersionImplementation().getContainedType()); return ReflectionUtil.newInstance(theTarget.getStructureFhirVersionEnum().getVersionImplementation().getContainedType());
} }

View File

@ -0,0 +1,5 @@
---
type: fix
issue: 4922
title: "R5 Subscription.filterBy.resourceType failed to deserialize because the deserializer skipped all elements named
'resourceType'. This has been changed so that only toplevel resourceType elements are skipped in the deserialization process."

View File

@ -0,0 +1,94 @@
package ca.uhn.fhir.jpa.subscription;
import ca.uhn.fhir.context.FhirContext;
import org.hl7.fhir.r5.model.Bundle;
import org.hl7.fhir.r5.model.Subscription;
import org.intellij.lang.annotations.Language;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertEquals;
public class SubscriptionTopicSerializationTest {
FhirContext ourFhirContext = FhirContext.forR5Cached();
@Test
void testSubscriptionDerialization() {
@Language("json")
String input = """
{
"resourceType": "Subscription",
"id": "2",
"status": "active",
"topic": "http://example.com/topic/test",
"reason": "Monitor new neonatal function (note, age will be determined by the monitor)",
"filterBy": [ {
"resourceType": "Encounter",
"filterParameter": "participation-type",
"comparator": "eq",
"value": "PRPF"
} ],
"channelType": {
"system": "http://terminology.hl7.org/CodeSystem/subscription-channel-type",
"code": "rest-hook"
},
"endpoint": "http://localhost:57333/fhir/context",
"contentType": "application/fhir+json"
}
""";
Subscription subscription = ourFhirContext.newJsonParser().parseResource(Subscription.class, input);
assertEquals("Subscription", subscription.getResourceType().name());
assertEquals("Encounter", subscription.getFilterByFirstRep().getResourceType());
// Also test the other direction
String serialized = ourFhirContext.newJsonParser().setPrettyPrint(true).encodeResourceToString(subscription);
assertEquals(input.trim(), serialized);
}
@Test
void testSubscriptionDerializationInBundle() {
@Language("json")
String input = """
{
"resourceType": "Bundle",
"id": "bundle-transaction",
"type": "transaction",
"entry": [ {
"fullUrl": "urn:uuid:61ebe359-bfdc-4613-8bf2-c5e300945f0a",
"resource": {
"resourceType": "Subscription",
"id": "2",
"status": "active",
"topic": "http://example.com/topic/test",
"reason": "Monitor new neonatal function (note, age will be determined by the monitor)",
"filterBy": [ {
"resourceType": "Encounter",
"filterParameter": "participation-type",
"comparator": "eq",
"value": "PRPF"
} ],
"channelType": {
"system": "http://terminology.hl7.org/CodeSystem/subscription-channel-type",
"code": "rest-hook"
},
"endpoint": "http://localhost:57333/fhir/context",
"contentType": "application/fhir+json"
},
"request": {
"method": "POST",
"url": "Subscription"
}
} ]
}
""";
Bundle bundle = ourFhirContext.newJsonParser().parseResource(Bundle.class, input);
Subscription subscription = (Subscription) bundle.getEntry().get(0).getResource();
assertEquals("Subscription", subscription.getResourceType().name());
assertEquals("Encounter", subscription.getFilterByFirstRep().getResourceType());
// Also test the other direction
String serialized = ourFhirContext.newJsonParser().setPrettyPrint(true).encodeResourceToString(bundle);
assertEquals(input.trim(), serialized);
}
}