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
This commit is contained in:
volodymyr-korzh 2024-02-06 18:04:03 -07:00 committed by GitHub
parent 8c16f57c05
commit 8e69170c89
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 150 additions and 8 deletions

View File

@ -1413,14 +1413,18 @@ class ParserState<T> {
myErrorHandler.invalidValue(location, value, "Attribute value must not be empty (\"\")");
} else {
if ("decimal".equals(myTypeName)) {
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 ("decimal".equals(myTypeName)) {
if (value != null)
if (value.startsWith(".") && NumberUtils.isDigits(value.substring(1))) {
value = "0" + value;
} else {
@ -1429,6 +1433,7 @@ class ParserState<T> {
}
}
}
}
try {
myInstance.setValueAsString(value);

View File

@ -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);

View File

@ -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."

View File

@ -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();

View File

@ -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
*

View File

@ -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"
}
]
}

View File

@ -0,0 +1,26 @@
<Observation xmlns="http://hl7.org/fhir">
<id value="0d87f02c-da2c-4551-9ead-2956f0165a4f"></id>
<code>
<coding>
<system value="http://loinc.org"></system>
<code value="8867-4"></code>
</coding>
</code>
<valueString value="observationValue"></valueString>
<status value="final"></status>
<referenceRange>
<low>
<value value="-3.0"/>
<unit value="mmol/l"/>
<system value="Home"/>
<code value="mmol/l"/>
</low>
<high>
<value value="+3.0"/>
<unit value="mmol/l"/>
<system value="Home"/>
<code value="mmol/l"/>
</high>
<text value="-3.0 mmol/l - +3.0 mmol/l"/>
</referenceRange>
</Observation>