Jackson Mapper 생성을 newNumberSafeMapper 이용으로 통일

This commit is contained in:
curry772
2026-08-27 16:56:08 +09:00
parent 82b7c779f1
commit 0f02f4d261
8 changed files with 53 additions and 11 deletions
@@ -7,6 +7,7 @@ import com.eactive.eai.adapter.http.client.HttpClientAdapterVO;
import com.eactive.eai.common.TransactionContextKeys; import com.eactive.eai.common.TransactionContextKeys;
import com.eactive.eai.common.message.MessageType; import com.eactive.eai.common.message.MessageType;
import com.eactive.eai.common.util.CommonLib; import com.eactive.eai.common.util.CommonLib;
import com.eactive.eai.common.util.JacksonUtil;
import com.eactive.eai.common.util.TxFileLogger; import com.eactive.eai.common.util.TxFileLogger;
import org.apache.commons.httpclient.HttpStatus; import org.apache.commons.httpclient.HttpStatus;
@@ -60,7 +61,9 @@ public class HttpClient5AdapterServiceBody extends HttpClient5AdapterServiceSupp
} }
if(MessageType.JSON.equals(prop.getProperty("messageType"))) { 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 jsonNode = (ObjectNode) mapper.readTree(sendData);
ObjectNode headerPart = (ObjectNode) jsonNode.get("header_part"); ObjectNode headerPart = (ObjectNode) jsonNode.get("header_part");
@@ -13,12 +13,15 @@ import org.apache.commons.lang3.StringUtils;
import com.eactive.eai.adapter.AdapterManager; import com.eactive.eai.adapter.AdapterManager;
import com.eactive.eai.adapter.http.dynamic.HttpAdapterServiceKey; import com.eactive.eai.adapter.http.dynamic.HttpAdapterServiceKey;
import com.eactive.eai.adapter.http.dynamic.filter.HttpAdapterFilter; 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.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode; import com.fasterxml.jackson.databind.node.ObjectNode;
public class JsonToStdConverterFilter implements HttpAdapterFilter { public class JsonToStdConverterFilter implements HttpAdapterFilter {
private ObjectMapper mapper = new ObjectMapper(); // 파싱 후 rootNode.toString() 으로 재직렬화하므로 숫자 자릿수가 유실되지 않는 mapper 를 쓴다.
// 기본 ObjectMapper 는 100000000.00 을 1.0E8 로 바꿔버린다.
private ObjectMapper mapper = JacksonUtil.newNumberSafeMapper();
@Override @Override
public Object doPreFilter(String adptGrpName, String adptName, Object message, Properties prop, public Object doPreFilter(String adptGrpName, String adptName, Object message, Properties prop,
@@ -11,6 +11,7 @@ import org.apache.commons.lang3.StringUtils;
import com.eactive.eai.adapter.AdapterManager; import com.eactive.eai.adapter.AdapterManager;
import com.eactive.eai.adapter.http.dynamic.filter.HttpAdapterFilter; 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.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonMappingException; import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.JsonNode;
@@ -19,7 +20,9 @@ import com.fasterxml.jackson.databind.node.ObjectNode;
public class KbankEaiJsonParseFilter implements HttpAdapterFilter { public class KbankEaiJsonParseFilter implements HttpAdapterFilter {
private ObjectMapper mapper = new ObjectMapper(); // 파싱 후 재직렬화하므로 숫자 자릿수가 유실되지 않는 mapper 를 쓴다.
// 기본 ObjectMapper 는 100000000.00 을 1.0E8 로 바꿔버린다.
private ObjectMapper mapper = JacksonUtil.newNumberSafeMapper();
@Override @Override
public Object doPreFilter(String adptGrpName, String adptName, Object message, Properties prop, public Object doPreFilter(String adptGrpName, String adptName, Object message, Properties prop,
@@ -6,10 +6,12 @@ import java.util.regex.Matcher;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.JsonMappingException; import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ArrayNode; import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.JsonNodeFactory;
import com.fasterxml.jackson.databind.node.ObjectNode; import com.fasterxml.jackson.databind.node.ObjectNode;
import org.json.simple.JSONObject; import org.json.simple.JSONObject;
@@ -35,9 +37,23 @@ public final class JacksonUtil {
private static final Pattern TOKEN_PATTERN = Pattern.compile("([^\\[\\]]*)((?:\\[\\d+\\])*)"); private static final Pattern TOKEN_PATTERN = Pattern.compile("([^\\[\\]]*)((?:\\[\\d+\\])*)");
private static final Pattern INDEX_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() { private JacksonUtil() {
// 인스턴스화 방지 // 인스턴스화 방지
@@ -18,6 +18,7 @@ import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ArrayNode; import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.JsonNodeFactory;
import com.fasterxml.jackson.databind.node.JsonNodeType; import com.fasterxml.jackson.databind.node.JsonNodeType;
public class JsonReader implements StandardReader { public class JsonReader implements StandardReader {
@@ -43,6 +44,10 @@ public class JsonReader implements StandardReader {
JsonParser parser = null; JsonParser parser = null;
mapper = new ObjectMapper(); mapper = new ObjectMapper();
mapper.enable(DeserializationFeature.USE_BIG_DECIMAL_FOR_FLOATS); 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(); factory = mapper.getFactory();
try { try {
parser = factory.createParser(jsonString); parser = factory.createParser(jsonString);
@@ -2,6 +2,7 @@ package com.eactive.eai.util;
import org.json.simple.JSONObject; import org.json.simple.JSONObject;
import com.eactive.eai.common.util.JacksonUtil;
import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ArrayNode; 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 시 파싱 횟수 절감 // JsonNode 기반 단일 파싱 API — 연속 get/set 시 파싱 횟수 절감
@@ -2,6 +2,7 @@ package com.eactive.eai.util.json;
import java.util.Map; import java.util.Map;
import com.eactive.eai.common.util.JacksonUtil;
import com.eactive.eai.common.util.Logger; import com.eactive.eai.common.util.Logger;
import com.eactive.eai.util.json.transformer.ValueTransformer; import com.eactive.eai.util.json.transformer.ValueTransformer;
import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.core.JsonProcessingException;
@@ -14,7 +15,9 @@ import com.jayway.jsonpath.spi.mapper.JacksonMappingProvider;
public class JsonPathsTransform { public class JsonPathsTransform {
static Logger logger = Logger.getLogger(Logger.LOGGER_ADAPTER); 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 <T, R> String modifyValuesAtPaths(String jsonString, public static <T, R> String modifyValuesAtPaths(String jsonString,
Map<String, ValueTransformer<T, R>> pathTransformerMap, boolean isPretty) { Map<String, ValueTransformer<T, R>> pathTransformerMap, boolean isPretty) {
@@ -23,9 +26,11 @@ public class JsonPathsTransform {
// DocumentContext documentContext = JsonPath.parse(jsonString); // DocumentContext documentContext = JsonPath.parse(jsonString);
// 변경헤도 별차이가 없음. // 변경헤도 별차이가 없음.
// provider 에 mapper 를 넘기지 않으면 json-path 가 자체 기본 ObjectMapper 를 쓰게 되어
// documentContext.jsonString() 단계에서 이미 숫자 자릿수가 유실된다.
Configuration conf = Configuration.builder() Configuration conf = Configuration.builder()
.jsonProvider(new JacksonJsonNodeJsonProvider()) .jsonProvider(new JacksonJsonNodeJsonProvider(objectMapper))
.mappingProvider(new JacksonMappingProvider()) .mappingProvider(new JacksonMappingProvider(objectMapper))
.build(); .build();
DocumentContext documentContext = JsonPath.using(conf).parse(jsonString); DocumentContext documentContext = JsonPath.using(conf).parse(jsonString);
@@ -2,6 +2,7 @@ package com.eactive.eai.util.json;
import java.util.Map; import java.util.Map;
import com.eactive.eai.common.util.JacksonUtil;
import com.eactive.eai.common.util.Logger; import com.eactive.eai.common.util.Logger;
import com.eactive.eai.util.json.transformer.ValueTransformer; import com.eactive.eai.util.json.transformer.ValueTransformer;
import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.JsonNode;
@@ -11,7 +12,9 @@ import com.fasterxml.jackson.databind.node.ObjectNode;
public class JsonSimplePathsTransform { public class JsonSimplePathsTransform {
static Logger logger = Logger.getLogger(Logger.LOGGER_ADAPTER); 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 <T, R> String modifyValuesAtPaths(String jsonString, public static <T, R> String modifyValuesAtPaths(String jsonString,
Map<String, ValueTransformer<T, R>> pathTransformerMap, boolean isPretty) { Map<String, ValueTransformer<T, R>> pathTransformerMap, boolean isPretty) {