From 8e69170c89b5267028d222a2dd78426bb5809568 Mon Sep 17 00:00:00 2001 From: volodymyr-korzh <132366313+volodymyr-korzh@users.noreply.github.com> Date: Tue, 6 Feb 2024 18:04:03 -0700 Subject: [PATCH] Xml encoded fhir resource created with decimal element that has leading plus sign value couldn't be retrieved or modified (#5670) * XML encoded FHIR resource created with decimal element that has leading plus sign value couldn't be retrieved or modified - implementation --- .../java/ca/uhn/fhir/parser/ParserState.java | 19 ++++-- .../parser/json/jackson/JacksonStructure.java | 5 +- ...ource-with-leading-plus-decimal-value.yaml | 6 ++ .../ca/uhn/fhir/parser/XmlParserR4Test.java | 14 ++++ .../parser/jsonlike/JsonLikeParserTest.java | 24 +++++++ ...ion-decimal-element-with-leading-plus.json | 64 +++++++++++++++++++ ...tion-decimal-element-with-leading-plus.xml | 26 ++++++++ 7 files changed, 150 insertions(+), 8 deletions(-) create mode 100644 hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/7_2_0/5667-fix-parsing-xml-encoded-fhir-resource-with-leading-plus-decimal-value.yaml create mode 100644 hapi-fhir-structures-r4/src/test/resources/observation-decimal-element-with-leading-plus.json create mode 100644 hapi-fhir-structures-r4/src/test/resources/observation-decimal-element-with-leading-plus.xml diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/parser/ParserState.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/parser/ParserState.java index 62983e9e5e7..8e07ade6766 100644 --- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/parser/ParserState.java +++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/parser/ParserState.java @@ -1413,14 +1413,18 @@ class ParserState { myErrorHandler.invalidValue(location, value, "Attribute value must not be empty (\"\")"); } else { - /* - * It may be possible to clean this up somewhat once the following PR is hopefully merged: - * https://github.com/FasterXML/jackson-core/pull/611 - * - * See TolerantJsonParser - */ if ("decimal".equals(myTypeName)) { - if (value != null) + if (value != null) { + // remove leading plus sign from decimal value + if (value.startsWith("+")) { + value = value.substring(1); + } + /* + * It may be possible to clean this up somewhat once the following PR is hopefully merged: + * https://github.com/FasterXML/jackson-core/pull/611 + * + * See TolerantJsonParser + */ if (value.startsWith(".") && NumberUtils.isDigits(value.substring(1))) { value = "0" + value; } else { @@ -1428,6 +1432,7 @@ class ParserState { value = value.substring(1); } } + } } try { diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/parser/json/jackson/JacksonStructure.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/parser/json/jackson/JacksonStructure.java index 160a976bea3..708223cf917 100644 --- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/parser/json/jackson/JacksonStructure.java +++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/parser/json/jackson/JacksonStructure.java @@ -30,6 +30,7 @@ import com.fasterxml.jackson.core.JsonGenerator; import com.fasterxml.jackson.core.JsonParser; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.core.StreamReadConstraints; +import com.fasterxml.jackson.core.json.JsonReadFeature; import com.fasterxml.jackson.databind.DeserializationFeature; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; @@ -406,7 +407,9 @@ public class JacksonStructure implements JsonLikeStructure { } private static ObjectMapper createObjectMapper() { - ObjectMapper retVal = JsonMapper.builder().build(); + ObjectMapper retVal = JsonMapper.builder() + .enable(JsonReadFeature.ALLOW_LEADING_PLUS_SIGN_FOR_NUMBERS) + .build(); retVal = retVal.setNodeFactory(new JsonNodeFactory(true)); retVal = retVal.enable(DeserializationFeature.USE_BIG_DECIMAL_FOR_FLOATS); retVal = retVal.enable(DeserializationFeature.FAIL_ON_TRAILING_TOKENS); diff --git a/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/7_2_0/5667-fix-parsing-xml-encoded-fhir-resource-with-leading-plus-decimal-value.yaml b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/7_2_0/5667-fix-parsing-xml-encoded-fhir-resource-with-leading-plus-decimal-value.yaml new file mode 100644 index 00000000000..88d8e20420a --- /dev/null +++ b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/7_2_0/5667-fix-parsing-xml-encoded-fhir-resource-with-leading-plus-decimal-value.yaml @@ -0,0 +1,6 @@ +--- +type: fix +issue: 5667 +title: "Previously, creating an XML encoded FHIR resource with a decimal element that has a leading plus sign value +would result in `JsonParseException` during the read operation from the database. Thus, making it impossible to +retrieve or modify such resources. This has been fixed." diff --git a/hapi-fhir-structures-r4/src/test/java/ca/uhn/fhir/parser/XmlParserR4Test.java b/hapi-fhir-structures-r4/src/test/java/ca/uhn/fhir/parser/XmlParserR4Test.java index 7d4f4dc9092..b4cfd5404a7 100644 --- a/hapi-fhir-structures-r4/src/test/java/ca/uhn/fhir/parser/XmlParserR4Test.java +++ b/hapi-fhir-structures-r4/src/test/java/ca/uhn/fhir/parser/XmlParserR4Test.java @@ -13,6 +13,7 @@ import static org.junit.jupiter.api.Assertions.assertNotNull; import java.io.IOException; import java.net.URL; +import ca.uhn.fhir.util.ClasspathUtil; import org.hl7.fhir.r4.model.Appointment; import org.hl7.fhir.r4.model.AuditEvent; import org.hl7.fhir.r4.model.Bundle; @@ -185,6 +186,19 @@ public class XmlParserR4Test extends BaseTest { assertEquals("12345", getPatientIdValue(bundle, 1)); } + @Test + public void testParseResource_withDecimalElementHasLeadingPlus_resourceParsedCorrectly() { + // setup + String text = ClasspathUtil.loadResource("observation-decimal-element-with-leading-plus.xml"); + + // execute + Observation observation = ourCtx.newXmlParser().parseResource(Observation.class, text); + + // verify + assertEquals("-3.0", observation.getReferenceRange().get(0).getLow().getValueElement().getValueAsString()); + assertEquals("3.0", observation.getReferenceRange().get(0).getHigh().getValueElement().getValueAsString()); + } + private String getPatientIdValue(Bundle input, int entry) { final DocumentReference documentReference = (DocumentReference)input.getEntry().get(entry).getResource(); final Patient patient = (Patient) documentReference.getSubject().getResource(); diff --git a/hapi-fhir-structures-r4/src/test/java/ca/uhn/fhir/parser/jsonlike/JsonLikeParserTest.java b/hapi-fhir-structures-r4/src/test/java/ca/uhn/fhir/parser/jsonlike/JsonLikeParserTest.java index d240c74e804..c48495bcfde 100644 --- a/hapi-fhir-structures-r4/src/test/java/ca/uhn/fhir/parser/jsonlike/JsonLikeParserTest.java +++ b/hapi-fhir-structures-r4/src/test/java/ca/uhn/fhir/parser/jsonlike/JsonLikeParserTest.java @@ -11,6 +11,7 @@ import ca.uhn.fhir.parser.json.JsonLikeStructure; import ca.uhn.fhir.parser.json.jackson.JacksonStructure; import ca.uhn.fhir.parser.view.ExtPatient; import ca.uhn.fhir.util.AttachmentUtil; +import ca.uhn.fhir.util.ClasspathUtil; import ca.uhn.fhir.util.ParametersUtil; import ca.uhn.fhir.util.TestUtil; import org.apache.commons.io.IOUtils; @@ -19,6 +20,7 @@ import org.hl7.fhir.instance.model.api.IBaseResource; import org.hl7.fhir.instance.model.api.ICompositeType; import org.hl7.fhir.r4.model.Extension; import org.hl7.fhir.r4.model.IntegerType; +import org.hl7.fhir.r4.model.Observation; import org.hl7.fhir.r4.model.Patient; import org.hl7.fhir.r4.model.Reference; import org.junit.jupiter.api.AfterAll; @@ -31,6 +33,7 @@ import java.io.StringReader; import java.io.Writer; import java.math.BigDecimal; import java.math.BigInteger; +import java.net.URL; import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; @@ -84,6 +87,27 @@ public class JsonLikeParserTest { } + /** + * Test that json number values with a leading plus sign are parsed without exception. + * Previously, it was possible to save resources with leading plus sign numbers, e.g., "value": +3.0. + * To ensure that we could read such resources back, the ObjectMapper configuration was updated by enabling: + * {@link com.fasterxml.jackson.core.json.JsonReadFeature#ALLOW_LEADING_PLUS_SIGN_FOR_NUMBERS} + * Reproduces: https://github.com/hapifhir/hapi-fhir/issues/5667 + */ + @Test + public void testJsonLikeParser_resourceHasDecimalElementWithLeadingPlus_isParsedCorrectly() { + // setup + String text = ClasspathUtil.loadResource("observation-decimal-element-with-leading-plus.json"); + IJsonLikeParser jsonLikeParser = (IJsonLikeParser) ourCtx.newJsonParser(); + + // execute + IBaseResource resource = jsonLikeParser.parseResource(text); + + // validate + Observation observation = (Observation) resource; + assertEquals("3.0", observation.getReferenceRange().get(0).getHigh().getValueElement().getValueAsString()); + } + /** * Test JSON-Like writer using custom stream writer * diff --git a/hapi-fhir-structures-r4/src/test/resources/observation-decimal-element-with-leading-plus.json b/hapi-fhir-structures-r4/src/test/resources/observation-decimal-element-with-leading-plus.json new file mode 100644 index 00000000000..221d88ed142 --- /dev/null +++ b/hapi-fhir-structures-r4/src/test/resources/observation-decimal-element-with-leading-plus.json @@ -0,0 +1,64 @@ +{ + "resourceType": "Observation", + "id": "1355", + "meta": { + "versionId": "1", + "lastUpdated": "2024-02-02T10:00:08.286-07:00", + "source": "#rxekXV5y3UZKAwxF" + }, + "identifier": [ + { + "system": "http://TEST.nl/fhir/NamingSystem/laboratory_observations", + "value": "H_2211280010-BEART" + } + ], + "status": "preliminary", + "category": [ + { + "coding": [ + { + "system": "5-Step briefing | SNOMED International", + "code": "49581000146104", + "display": "Laboratory test finding (finding)" + } + ] + } + ], + "code": { + "coding": [ + { + "system": "Home – LOINC", + "code": "8889-8", + "display": "Heart rate by Pulse oximeter" + } + ] + }, + "subject": { + "reference": "Patient/1354", + "display": "Jongetje. Jongensnaamnaam van" + }, + "effectiveDateTime": "2022-11-28T16:09:00+01:00", + "performer": [ + { + "reference": "Practitioner/P8", + "display": "TEST" + } + ], + "referenceRange": [ + { + "low": { + "value": -3.0, + "unit": "mmol/l", + "system": "Home", + "code": "mmol/l" + }, + "high": { + "value": +3.0, + "unit": "mmol/l", + "system": "Home", + "code": "mmol/l" + }, + "text": "-3.0 mmol/l - +3.0 mmol/l" + } + ] +} diff --git a/hapi-fhir-structures-r4/src/test/resources/observation-decimal-element-with-leading-plus.xml b/hapi-fhir-structures-r4/src/test/resources/observation-decimal-element-with-leading-plus.xml new file mode 100644 index 00000000000..4c7de31dfec --- /dev/null +++ b/hapi-fhir-structures-r4/src/test/resources/observation-decimal-element-with-leading-plus.xml @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + + + + + + + + + +