From 0f02f4d261915a48844425b8b2e39f68e7bd1958 Mon Sep 17 00:00:00 2001 From: curry772 Date: Thu, 27 Aug 2026 16:56:08 +0900 Subject: [PATCH] =?UTF-8?q?Jackson=20Mapper=20=EC=83=9D=EC=84=B1=EC=9D=84?= =?UTF-8?q?=20newNumberSafeMapper=20=EC=9D=B4=EC=9A=A9=EC=9C=BC=EB=A1=9C?= =?UTF-8?q?=20=ED=86=B5=EC=9D=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../impl/HttpClient5AdapterServiceBody.java | 5 ++++- .../custom/JsonToStdConverterFilter.java | 5 ++++- .../custom/KbankEaiJsonParseFilter.java | 5 ++++- .../eactive/eai/common/util/JacksonUtil.java | 22 ++++++++++++++++--- .../eai/message/parser/JsonReader.java | 5 +++++ .../com/eactive/eai/util/JsonPathUtil.java | 6 ++++- .../eai/util/json/JsonPathsTransform.java | 11 +++++++--- .../util/json/JsonSimplePathsTransform.java | 5 ++++- 8 files changed, 53 insertions(+), 11 deletions(-) diff --git a/src/main/java/com/eactive/eai/adapter/http/client/impl/HttpClient5AdapterServiceBody.java b/src/main/java/com/eactive/eai/adapter/http/client/impl/HttpClient5AdapterServiceBody.java index 511072a..a651da0 100644 --- a/src/main/java/com/eactive/eai/adapter/http/client/impl/HttpClient5AdapterServiceBody.java +++ b/src/main/java/com/eactive/eai/adapter/http/client/impl/HttpClient5AdapterServiceBody.java @@ -7,6 +7,7 @@ import com.eactive.eai.adapter.http.client.HttpClientAdapterVO; import com.eactive.eai.common.TransactionContextKeys; import com.eactive.eai.common.message.MessageType; import com.eactive.eai.common.util.CommonLib; +import com.eactive.eai.common.util.JacksonUtil; import com.eactive.eai.common.util.TxFileLogger; import org.apache.commons.httpclient.HttpStatus; @@ -60,7 +61,9 @@ public class HttpClient5AdapterServiceBody extends HttpClient5AdapterServiceSupp } if(MessageType.JSON.equals(prop.getProperty("messageType"))) { - ObjectMapper mapper = new ObjectMapper(); + // 파싱 후 재직렬화하므로 숫자 자릿수가 유실되지 않는 mapper 를 쓴다. + // 기본 ObjectMapper 는 100000000.00 을 1.0E8 로 바꿔버린다. + ObjectMapper mapper = JacksonUtil.newNumberSafeMapper(); ObjectNode jsonNode = (ObjectNode) mapper.readTree(sendData); ObjectNode headerPart = (ObjectNode) jsonNode.get("header_part"); diff --git a/src/main/java/com/eactive/eai/adapter/http/dynamic/filter/custom/JsonToStdConverterFilter.java b/src/main/java/com/eactive/eai/adapter/http/dynamic/filter/custom/JsonToStdConverterFilter.java index 1df1583..f02e309 100644 --- a/src/main/java/com/eactive/eai/adapter/http/dynamic/filter/custom/JsonToStdConverterFilter.java +++ b/src/main/java/com/eactive/eai/adapter/http/dynamic/filter/custom/JsonToStdConverterFilter.java @@ -13,12 +13,15 @@ import org.apache.commons.lang3.StringUtils; import com.eactive.eai.adapter.AdapterManager; import com.eactive.eai.adapter.http.dynamic.HttpAdapterServiceKey; import com.eactive.eai.adapter.http.dynamic.filter.HttpAdapterFilter; +import com.eactive.eai.common.util.JacksonUtil; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.node.ObjectNode; public class JsonToStdConverterFilter implements HttpAdapterFilter { - private ObjectMapper mapper = new ObjectMapper(); + // 파싱 후 rootNode.toString() 으로 재직렬화하므로 숫자 자릿수가 유실되지 않는 mapper 를 쓴다. + // 기본 ObjectMapper 는 100000000.00 을 1.0E8 로 바꿔버린다. + private ObjectMapper mapper = JacksonUtil.newNumberSafeMapper(); @Override public Object doPreFilter(String adptGrpName, String adptName, Object message, Properties prop, diff --git a/src/main/java/com/eactive/eai/adapter/http/dynamic/filter/custom/KbankEaiJsonParseFilter.java b/src/main/java/com/eactive/eai/adapter/http/dynamic/filter/custom/KbankEaiJsonParseFilter.java index d0d6fc0..b1d0027 100644 --- a/src/main/java/com/eactive/eai/adapter/http/dynamic/filter/custom/KbankEaiJsonParseFilter.java +++ b/src/main/java/com/eactive/eai/adapter/http/dynamic/filter/custom/KbankEaiJsonParseFilter.java @@ -11,6 +11,7 @@ import org.apache.commons.lang3.StringUtils; import com.eactive.eai.adapter.AdapterManager; import com.eactive.eai.adapter.http.dynamic.filter.HttpAdapterFilter; +import com.eactive.eai.common.util.JacksonUtil; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.JsonMappingException; import com.fasterxml.jackson.databind.JsonNode; @@ -19,7 +20,9 @@ import com.fasterxml.jackson.databind.node.ObjectNode; public class KbankEaiJsonParseFilter implements HttpAdapterFilter { - private ObjectMapper mapper = new ObjectMapper(); + // 파싱 후 재직렬화하므로 숫자 자릿수가 유실되지 않는 mapper 를 쓴다. + // 기본 ObjectMapper 는 100000000.00 을 1.0E8 로 바꿔버린다. + private ObjectMapper mapper = JacksonUtil.newNumberSafeMapper(); @Override public Object doPreFilter(String adptGrpName, String adptName, Object message, Properties prop, diff --git a/src/main/java/com/eactive/eai/common/util/JacksonUtil.java b/src/main/java/com/eactive/eai/common/util/JacksonUtil.java index afd150f..4bdce14 100644 --- a/src/main/java/com/eactive/eai/common/util/JacksonUtil.java +++ b/src/main/java/com/eactive/eai/common/util/JacksonUtil.java @@ -6,10 +6,12 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.DeserializationFeature; import com.fasterxml.jackson.databind.JsonMappingException; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.node.ArrayNode; +import com.fasterxml.jackson.databind.node.JsonNodeFactory; import com.fasterxml.jackson.databind.node.ObjectNode; import org.json.simple.JSONObject; @@ -35,10 +37,24 @@ public final class JacksonUtil { private static final Pattern TOKEN_PATTERN = Pattern.compile("([^\\[\\]]*)((?:\\[\\d+\\])*)"); private static final Pattern INDEX_PATTERN = Pattern.compile("\\[(\\d+)\\]"); - private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper(); + private static final ObjectMapper OBJECT_MAPPER = newNumberSafeMapper(); + + /** + * JSON 숫자를 double 로 좁히지 않고 BigDecimal 로, 수신한 자릿수 그대로 유지하는 ObjectMapper. + * + * readTree() 로 파싱한 뒤 writeValueAsString() 으로 다시 문자열을 만드는 왕복에서, + * 기본 설정이면 100000000.00 이 1.0E8 로 변형된다. + * USE_BIG_DECIMAL_FOR_FLOATS 만 켜고 withExactBigDecimals(true) 를 빼면 기본 + * JsonNodeFactory 가 stripTrailingZeros() 를 적용해 scale 이 음수가 되어 1E+8 이 된다. + * 두 옵션을 함께 켜야 수신한 값이 그대로 보존된다. + */ + public static ObjectMapper newNumberSafeMapper() { + ObjectMapper objectMapper = new ObjectMapper(); + objectMapper.enable(DeserializationFeature.USE_BIG_DECIMAL_FOR_FLOATS); + objectMapper.setNodeFactory(JsonNodeFactory.withExactBigDecimals(true)); + return objectMapper; + } - - private JacksonUtil() { // 인스턴스화 방지 } diff --git a/src/main/java/com/eactive/eai/message/parser/JsonReader.java b/src/main/java/com/eactive/eai/message/parser/JsonReader.java index c2c494d..a25aeb5 100644 --- a/src/main/java/com/eactive/eai/message/parser/JsonReader.java +++ b/src/main/java/com/eactive/eai/message/parser/JsonReader.java @@ -18,6 +18,7 @@ import com.fasterxml.jackson.databind.DeserializationFeature; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.node.ArrayNode; +import com.fasterxml.jackson.databind.node.JsonNodeFactory; import com.fasterxml.jackson.databind.node.JsonNodeType; public class JsonReader implements StandardReader { @@ -43,6 +44,10 @@ public class JsonReader implements StandardReader { JsonParser parser = null; mapper = new ObjectMapper(); mapper.enable(DeserializationFeature.USE_BIG_DECIMAL_FOR_FLOATS); + // USE_BIG_DECIMAL_FOR_FLOATS 만 켜면 기본 JsonNodeFactory 가 DecimalNode 생성 시 + // stripTrailingZeros() 를 적용해 scale 이 음수가 되고, 그 결과 + // 100000000.00 이 1E+8 로 변형된다. exact 모드로 수신한 자릿수를 보존한다. + mapper.setNodeFactory(JsonNodeFactory.withExactBigDecimals(true)); factory = mapper.getFactory(); try { parser = factory.createParser(jsonString); diff --git a/src/main/java/com/eactive/eai/util/JsonPathUtil.java b/src/main/java/com/eactive/eai/util/JsonPathUtil.java index ff24a96..ae9a733 100644 --- a/src/main/java/com/eactive/eai/util/JsonPathUtil.java +++ b/src/main/java/com/eactive/eai/util/JsonPathUtil.java @@ -2,6 +2,7 @@ package com.eactive.eai.util; import org.json.simple.JSONObject; +import com.eactive.eai.common.util.JacksonUtil; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.node.ArrayNode; @@ -15,7 +16,10 @@ public class JsonPathUtil { } - private static final ObjectMapper objectMapper = new ObjectMapper(); + // readTree() 로 파싱한 뒤 writeValueAsString() 으로 되돌리는 왕복이 잦으므로, + // 숫자 자릿수가 유실되지 않는 mapper 를 쓴다. + // 기본 ObjectMapper 는 100000000.00 을 1.0E8 로 바꿔버린다. + private static final ObjectMapper objectMapper = JacksonUtil.newNumberSafeMapper(); // --------------------------------------------------------------- // JsonNode 기반 단일 파싱 API — 연속 get/set 시 파싱 횟수 절감 diff --git a/src/main/java/com/eactive/eai/util/json/JsonPathsTransform.java b/src/main/java/com/eactive/eai/util/json/JsonPathsTransform.java index ca0600e..1d378d2 100644 --- a/src/main/java/com/eactive/eai/util/json/JsonPathsTransform.java +++ b/src/main/java/com/eactive/eai/util/json/JsonPathsTransform.java @@ -2,6 +2,7 @@ package com.eactive.eai.util.json; import java.util.Map; +import com.eactive.eai.common.util.JacksonUtil; import com.eactive.eai.common.util.Logger; import com.eactive.eai.util.json.transformer.ValueTransformer; import com.fasterxml.jackson.core.JsonProcessingException; @@ -14,7 +15,9 @@ import com.jayway.jsonpath.spi.mapper.JacksonMappingProvider; public class JsonPathsTransform { static Logger logger = Logger.getLogger(Logger.LOGGER_ADAPTER); - private static final ObjectMapper objectMapper = new ObjectMapper(); + // 파싱 후 재직렬화하므로 숫자 자릿수가 유실되지 않는 mapper 를 쓴다. + // 기본 ObjectMapper 는 100000000.00 을 1.0E8 로 바꿔버린다. + private static final ObjectMapper objectMapper = JacksonUtil.newNumberSafeMapper(); public static String modifyValuesAtPaths(String jsonString, Map> pathTransformerMap, boolean isPretty) { @@ -23,9 +26,11 @@ public class JsonPathsTransform { // DocumentContext documentContext = JsonPath.parse(jsonString); // 변경헤도 별차이가 없음. + // provider 에 mapper 를 넘기지 않으면 json-path 가 자체 기본 ObjectMapper 를 쓰게 되어 + // documentContext.jsonString() 단계에서 이미 숫자 자릿수가 유실된다. Configuration conf = Configuration.builder() - .jsonProvider(new JacksonJsonNodeJsonProvider()) - .mappingProvider(new JacksonMappingProvider()) + .jsonProvider(new JacksonJsonNodeJsonProvider(objectMapper)) + .mappingProvider(new JacksonMappingProvider(objectMapper)) .build(); DocumentContext documentContext = JsonPath.using(conf).parse(jsonString); diff --git a/src/main/java/com/eactive/eai/util/json/JsonSimplePathsTransform.java b/src/main/java/com/eactive/eai/util/json/JsonSimplePathsTransform.java index 2af3b2b..a3e5d67 100644 --- a/src/main/java/com/eactive/eai/util/json/JsonSimplePathsTransform.java +++ b/src/main/java/com/eactive/eai/util/json/JsonSimplePathsTransform.java @@ -2,6 +2,7 @@ package com.eactive.eai.util.json; import java.util.Map; +import com.eactive.eai.common.util.JacksonUtil; import com.eactive.eai.common.util.Logger; import com.eactive.eai.util.json.transformer.ValueTransformer; import com.fasterxml.jackson.databind.JsonNode; @@ -11,7 +12,9 @@ import com.fasterxml.jackson.databind.node.ObjectNode; public class JsonSimplePathsTransform { static Logger logger = Logger.getLogger(Logger.LOGGER_ADAPTER); - private static final ObjectMapper objectMapper = new ObjectMapper(); + // 파싱 후 재직렬화하므로 숫자 자릿수가 유실되지 않는 mapper 를 쓴다. + // 기본 ObjectMapper 는 100000000.00 을 1.0E8 로 바꿔버린다. + private static final ObjectMapper objectMapper = JacksonUtil.newNumberSafeMapper(); public static String modifyValuesAtPaths(String jsonString, Map> pathTransformerMap, boolean isPretty) {