오류코드 메시지를 프로퍼티 그룹에 등록하여 매핑 치환하는 AdapterErrorMsgHandler 개발
- AdapterErrorMessageHandler{CODE_CONVERT} 에 등록
- TemplateCodeConvertAdapterErrorMsgHandler json만 지원하는 handler 개발
This commit is contained in:
@@ -89,7 +89,7 @@ public class TemplateAdapterErrorMsgHandler implements AdapterErrorMessageHandle
|
||||
|
||||
private static final Logger logger = Logger.getLogger(Logger.LOGGER_ADAPTER);
|
||||
|
||||
/** AdapterPropManager 에서 템플릿을 조회할 프로퍼티 그룹 이름 */
|
||||
/** PropManager 에서 템플릿을 조회할 프로퍼티 그룹 이름 */
|
||||
static final String PROP_GROUP = "AdapterErrorMessageHandler";
|
||||
|
||||
/** callProp 참조 변수 접두어: ${callprop.키} */
|
||||
|
||||
+126
@@ -0,0 +1,126 @@
|
||||
package com.eactive.eai.adapter.handler;
|
||||
|
||||
import java.util.Properties;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import com.eactive.eai.common.message.EAIMessage;
|
||||
import com.eactive.eai.common.property.PropManager;
|
||||
import com.eactive.eai.common.util.Logger;
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.databind.node.ObjectNode;
|
||||
|
||||
|
||||
public class TemplateCodeConvertAdapterErrorMsgHandler extends TemplateAdapterErrorMsgHandler {
|
||||
|
||||
private static final Logger logger = Logger.getLogger(Logger.LOGGER_ADAPTER);
|
||||
|
||||
/** PropManager 에서 코드 변환 설정을 조회할 프로퍼티 그룹 이름 */
|
||||
static final String PROP_GROUP = "AdapterErrorMessageHandler{CODE_CONVERT}";
|
||||
|
||||
private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();
|
||||
|
||||
@Override
|
||||
public Object generateNonStandardErrorResponseMessage(
|
||||
String inboundAdapterGroupName,
|
||||
String inboundAdapterName,
|
||||
Properties callProp,
|
||||
Object outboundRequestData,
|
||||
EAIMessage resEaiMsg) throws Exception {
|
||||
|
||||
Object responseMsessage = super.generateNonStandardErrorResponseMessage(
|
||||
inboundAdapterGroupName,
|
||||
inboundAdapterName,
|
||||
callProp,
|
||||
outboundRequestData,
|
||||
resEaiMsg);
|
||||
|
||||
logger.debug("generateNonStandardErrorResponseMessage - {}", responseMsessage);
|
||||
|
||||
if (!(responseMsessage instanceof String)) {
|
||||
return responseMsessage;
|
||||
}
|
||||
|
||||
String jsonStr = (String) responseMsessage;
|
||||
if (StringUtils.isBlank(jsonStr)) {
|
||||
return responseMsessage;
|
||||
}
|
||||
|
||||
Properties props = PropManager.getInstance().getProperties(PROP_GROUP);
|
||||
if (props == null) {
|
||||
return responseMsessage;
|
||||
}
|
||||
|
||||
String fieldsKey = inboundAdapterGroupName + ".convert.fields";
|
||||
String fieldsValue = props.getProperty(fieldsKey);
|
||||
if (StringUtils.isBlank(fieldsValue)) {
|
||||
return responseMsessage;
|
||||
}
|
||||
|
||||
JsonNode rootNode = OBJECT_MAPPER.readTree(jsonStr);
|
||||
boolean modified = false;
|
||||
|
||||
for (String rawField : fieldsValue.split(",")) {
|
||||
String fieldPath = rawField.trim();
|
||||
if (StringUtils.isBlank(fieldPath)) continue;
|
||||
|
||||
String currentValue = getJsonValue(rootNode, fieldPath);
|
||||
if (currentValue == null) continue;
|
||||
|
||||
// key: inboundAdapterGroupName.{fieldPath}.{현재값} → 폴백: ...{fieldPath}.default
|
||||
String mappingKey = inboundAdapterGroupName + "." + fieldPath + "." + currentValue;
|
||||
String newValue = props.getProperty(mappingKey);
|
||||
if (newValue == null) {
|
||||
String defaultKey = inboundAdapterGroupName + "." + fieldPath + ".default";
|
||||
newValue = props.getProperty(defaultKey);
|
||||
}
|
||||
if (newValue == null) continue;
|
||||
|
||||
setJsonValue(rootNode, fieldPath, newValue);
|
||||
modified = true;
|
||||
|
||||
if (logger.isDebug()) {
|
||||
logger.debug("code convert: field={}, {} -> {}", fieldPath, currentValue, newValue);
|
||||
}
|
||||
}
|
||||
|
||||
if (modified) {
|
||||
responseMsessage = OBJECT_MAPPER.writeValueAsString(rootNode);
|
||||
}
|
||||
|
||||
return responseMsessage;
|
||||
}
|
||||
|
||||
/**
|
||||
* dot 구분 경로로 JsonNode 에서 값을 꺼낸다.
|
||||
* 최종 노드가 값 노드(primitive)가 아니면 null 반환.
|
||||
*/
|
||||
private String getJsonValue(JsonNode node, String fieldPath) {
|
||||
JsonNode current = node;
|
||||
for (String part : fieldPath.split("\\.", -1)) {
|
||||
if (current == null || !current.isObject()) return null;
|
||||
current = current.get(part);
|
||||
}
|
||||
if (current == null || current.isNull() || !current.isValueNode()) return null;
|
||||
return current.asText();
|
||||
}
|
||||
|
||||
/**
|
||||
* dot 구분 경로로 ObjectNode 의 최종 필드 값을 newValue 로 교체한다.
|
||||
* 중간 경로가 ObjectNode 가 아니면 무시한다.
|
||||
*/
|
||||
private void setJsonValue(JsonNode rootNode, String fieldPath, String newValue) {
|
||||
String[] parts = fieldPath.split("\\.", -1);
|
||||
JsonNode current = rootNode;
|
||||
for (int i = 0; i < parts.length - 1; i++) {
|
||||
if (current == null || !current.isObject()) return;
|
||||
current = current.get(parts[i]);
|
||||
}
|
||||
if (current instanceof ObjectNode) {
|
||||
((ObjectNode) current).put(parts[parts.length - 1], newValue);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
+549
@@ -0,0 +1,549 @@
|
||||
package com.eactive.eai.adapter.handler;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertNull;
|
||||
import static org.mockito.ArgumentMatchers.anyString;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.Properties;
|
||||
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.DisplayName;
|
||||
import org.junit.jupiter.api.Nested;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.mockito.Mockito;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
|
||||
import com.eactive.eai.common.message.EAIMessage;
|
||||
import com.eactive.eai.common.property.PropManager;
|
||||
import com.eactive.eai.common.util.ApplicationContextProvider;
|
||||
import com.eactive.eai.message.StandardItem;
|
||||
import com.eactive.eai.message.StandardMessage;
|
||||
import com.eactive.eai.message.StandardType;
|
||||
|
||||
/**
|
||||
* TemplateCodeConvertAdapterErrorMsgHandler 단위테스트
|
||||
*
|
||||
* 검증 대상: generateNonStandardErrorResponseMessage
|
||||
* - 부모 클래스(TemplateAdapterErrorMsgHandler)가 반환한 JSON 문자열에서
|
||||
* PropManager(AdapterErrorMessageHandler{CODE_CONVERT} 그룹)에 등록된
|
||||
* 매핑 정보로 지정 필드 값을 변환한다.
|
||||
*/
|
||||
class TemplateCodeConvertAdapterErrorMsgHandlerTest {
|
||||
|
||||
private TemplateCodeConvertAdapterErrorMsgHandler handler;
|
||||
|
||||
@BeforeEach
|
||||
void setUp() {
|
||||
handler = new TemplateCodeConvertAdapterErrorMsgHandler();
|
||||
}
|
||||
|
||||
// ================================================================
|
||||
// 공통 헬퍼
|
||||
// ================================================================
|
||||
|
||||
private static StandardItem field(String name, String value) {
|
||||
return new StandardItem(name, 3, StandardType.FIELD, 1, 0, 300, 1, "", "", value, name);
|
||||
}
|
||||
|
||||
private static StandardItem group(String name) {
|
||||
return new StandardItem(name, 2, StandardType.GROUP, 1, 0, 0, 1, "", "", null, name);
|
||||
}
|
||||
|
||||
private StandardMessage buildMsg(String errCode, String errMsg) {
|
||||
StandardMessage msg = new StandardMessage();
|
||||
StandardItem msgGroup = group("MSG");
|
||||
StandardItem mainMsg = group("MAIN_MSG");
|
||||
mainMsg.addItem(field("outp_msg_cd", errCode));
|
||||
mainMsg.addItem(field("outp_msg_ctnt", errMsg));
|
||||
msgGroup.addItem(mainMsg);
|
||||
|
||||
StandardItem msgList = new StandardItem(
|
||||
"MSG_LIST", 2, StandardType.GRID, 0, 0, 0, 1, "", "", null, "MSG_LIST");
|
||||
msgList.addItem(field("outp_msg_cd", ""));
|
||||
msgList.addItem(field("outp_msg_ctnt", ""));
|
||||
msgGroup.addItem(msgList);
|
||||
msg.addItem(msgGroup);
|
||||
return msg;
|
||||
}
|
||||
|
||||
private EAIMessage toEaiMessage(StandardMessage msg) {
|
||||
EAIMessage eaiMessage = new EAIMessage();
|
||||
eaiMessage.setStandardMessage(msg);
|
||||
return eaiMessage;
|
||||
}
|
||||
|
||||
/**
|
||||
* ApplicationContextProvider 에 mock PropManager 를 주입한다.
|
||||
* 부모 클래스의 getProperty(group, key) 와
|
||||
* 자식 클래스의 getProperties(group) 을 동일한 mock 으로 처리한다.
|
||||
*/
|
||||
private void injectMockPropManager(PropManager mockPropManager) throws Exception {
|
||||
ApplicationContext mockCtx = Mockito.mock(ApplicationContext.class);
|
||||
Mockito.when(mockCtx.getBean(PropManager.class)).thenReturn(mockPropManager);
|
||||
Field ctxField = ApplicationContextProvider.class.getDeclaredField("context");
|
||||
ctxField.setAccessible(true);
|
||||
ctxField.set(null, mockCtx);
|
||||
}
|
||||
|
||||
/**
|
||||
* 부모 템플릿 결과가 될 JSON 과 코드 변환 설정을 함께 세팅하는 헬퍼.
|
||||
*
|
||||
* @param adapterGroupName 어댑터 그룹명
|
||||
* @param template 부모 핸들러에서 사용할 JSON 템플릿 문자열
|
||||
* @param convertProps PROP_GROUP(CODE_CONVERT) 에서 반환될 Properties (null 가능)
|
||||
*/
|
||||
private PropManager setupMock(String adapterGroupName, String template,
|
||||
Properties convertProps) throws Exception {
|
||||
PropManager mockProp = Mockito.mock(PropManager.class);
|
||||
// 부모 클래스: getProperty("AdapterErrorMessageHandler", "GROUP.template")
|
||||
Mockito.when(mockProp.getProperty(
|
||||
eq(TemplateAdapterErrorMsgHandler.PROP_GROUP),
|
||||
eq(adapterGroupName + ".template"))).thenReturn(template);
|
||||
// 자식 클래스: getProperties("AdapterErrorMessageHandler{CODE_CONVERT}")
|
||||
Mockito.when(mockProp.getProperties(
|
||||
eq(TemplateCodeConvertAdapterErrorMsgHandler.PROP_GROUP))).thenReturn(convertProps);
|
||||
injectMockPropManager(mockProp);
|
||||
return mockProp;
|
||||
}
|
||||
|
||||
/** convert.fields 와 매핑 항목들로 Properties 를 생성하는 헬퍼 */
|
||||
private static Properties convertProps(String adapterGroupName,
|
||||
String fields,
|
||||
String... mappings) {
|
||||
Properties p = new Properties();
|
||||
p.setProperty(adapterGroupName + ".convert.fields", fields);
|
||||
for (int i = 0; i < mappings.length - 1; i += 2) {
|
||||
p.setProperty(adapterGroupName + "." + mappings[i], mappings[i + 1]);
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
// ================================================================
|
||||
// 사전 조건 및 조기 반환
|
||||
// ================================================================
|
||||
|
||||
@Nested
|
||||
@DisplayName("사전 조건 – 조기 반환")
|
||||
class EarlyReturn {
|
||||
|
||||
@Test
|
||||
@DisplayName("부모 핸들러가 null 반환 시 null 그대로 반환")
|
||||
void 부모_null_반환시_null() throws Exception {
|
||||
PropManager mockProp = Mockito.mock(PropManager.class);
|
||||
// 템플릿 없음 → 부모 핸들러가 null 반환
|
||||
Mockito.when(mockProp.getProperty(anyString(), anyString())).thenReturn(null);
|
||||
injectMockPropManager(mockProp);
|
||||
|
||||
Object result = handler.generateNonStandardErrorResponseMessage(
|
||||
"MY_GROUP", "MY_ADAPTER", new Properties(), null,
|
||||
toEaiMessage(buildMsg("40000", "오류")));
|
||||
|
||||
assertNull(result);
|
||||
// getProperties 는 호출되지 않아야 함
|
||||
Mockito.verify(mockProp, Mockito.never())
|
||||
.getProperties(TemplateCodeConvertAdapterErrorMsgHandler.PROP_GROUP);
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("부모 핸들러가 빈 문자열 반환 시 그대로 반환 (변환 미수행)")
|
||||
void 부모_빈문자열_그대로_반환() throws Exception {
|
||||
setupMock("MY_GROUP", " ", null); // blank → 부모도 null 반환
|
||||
|
||||
Object result = handler.generateNonStandardErrorResponseMessage(
|
||||
"MY_GROUP", "MY_ADAPTER", new Properties(), null,
|
||||
toEaiMessage(buildMsg("40000", "오류")));
|
||||
|
||||
assertNull(result);
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("CODE_CONVERT 그룹의 Properties 가 null 이면 템플릿 결과 그대로 반환")
|
||||
void convert_props_null_시_원본_반환() throws Exception {
|
||||
String template = "{\"resCode\":\"${MSG.MAIN_MSG.outp_msg_cd}\"}";
|
||||
setupMock("MY_GROUP", template, null); // getProperties → null
|
||||
|
||||
Object result = handler.generateNonStandardErrorResponseMessage(
|
||||
"MY_GROUP", "MY_ADAPTER", new Properties(), null,
|
||||
toEaiMessage(buildMsg("40000", "오류")));
|
||||
|
||||
assertEquals("{\"resCode\":\"40000\"}", result);
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("convert.fields 키가 없으면 템플릿 결과 그대로 반환")
|
||||
void convert_fields_없으면_원본_반환() throws Exception {
|
||||
String template = "{\"resCode\":\"${MSG.MAIN_MSG.outp_msg_cd}\"}";
|
||||
// convert.fields 를 설정하지 않은 빈 Properties
|
||||
setupMock("MY_GROUP", template, new Properties());
|
||||
|
||||
Object result = handler.generateNonStandardErrorResponseMessage(
|
||||
"MY_GROUP", "MY_ADAPTER", new Properties(), null,
|
||||
toEaiMessage(buildMsg("40000", "오류")));
|
||||
|
||||
assertEquals("{\"resCode\":\"40000\"}", result);
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("convert.fields 가 공백이면 템플릿 결과 그대로 반환")
|
||||
void convert_fields_공백이면_원본_반환() throws Exception {
|
||||
String template = "{\"resCode\":\"${MSG.MAIN_MSG.outp_msg_cd}\"}";
|
||||
Properties cp = new Properties();
|
||||
cp.setProperty("MY_GROUP.convert.fields", " ");
|
||||
setupMock("MY_GROUP", template, cp);
|
||||
|
||||
Object result = handler.generateNonStandardErrorResponseMessage(
|
||||
"MY_GROUP", "MY_ADAPTER", new Properties(), null,
|
||||
toEaiMessage(buildMsg("40000", "오류")));
|
||||
|
||||
// 필드가 공백이므로 split 후 trim → blank → skip → 변환 없음
|
||||
assertEquals("{\"resCode\":\"40000\"}", result);
|
||||
}
|
||||
}
|
||||
|
||||
// ================================================================
|
||||
// 단순 필드 코드 변환
|
||||
// ================================================================
|
||||
|
||||
@Nested
|
||||
@DisplayName("단순 필드 코드 변환")
|
||||
class SimpleFieldConvert {
|
||||
|
||||
@Test
|
||||
@DisplayName("단일 필드 값 변환")
|
||||
void 단일_필드_변환() throws Exception {
|
||||
String template = "{\"resCode\":\"${MSG.MAIN_MSG.outp_msg_cd}\",\"resMessage\":\"${MSG.MAIN_MSG.outp_msg_ctnt}\"}";
|
||||
Properties cp = convertProps("GRP",
|
||||
"resCode",
|
||||
"resCode.40000", "TB_ERR_999");
|
||||
setupMock("GRP", template, cp);
|
||||
|
||||
Object result = handler.generateNonStandardErrorResponseMessage(
|
||||
"GRP", "ADP", new Properties(), null,
|
||||
toEaiMessage(buildMsg("40000", "Bad Request")));
|
||||
|
||||
assertEquals("{\"resCode\":\"TB_ERR_999\",\"resMessage\":\"Bad Request\"}", result);
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("여러 필드 동시 변환")
|
||||
void 여러_필드_변환() throws Exception {
|
||||
String template = "{\"resCode\":\"${MSG.MAIN_MSG.outp_msg_cd}\",\"resMessage\":\"${MSG.MAIN_MSG.outp_msg_ctnt}\"}";
|
||||
Properties cp = convertProps("GRP",
|
||||
"resCode,resMessage",
|
||||
"resCode.40000", "TB_ERR_999",
|
||||
"resMessage.40000", "요청파라미터에 문제가 있습니다.(필수값 입력오류)");
|
||||
setupMock("GRP", template, cp);
|
||||
|
||||
Object result = handler.generateNonStandardErrorResponseMessage(
|
||||
"GRP", "ADP", new Properties(), null,
|
||||
toEaiMessage(buildMsg("40000", "40000")));
|
||||
|
||||
assertEquals(
|
||||
"{\"resCode\":\"TB_ERR_999\",\"resMessage\":\"요청파라미터에 문제가 있습니다.(필수값 입력오류)\"}",
|
||||
result);
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("매핑에 없는 값은 원본 그대로 유지")
|
||||
void 매핑_없는_값_원본_유지() throws Exception {
|
||||
String template = "{\"resCode\":\"${MSG.MAIN_MSG.outp_msg_cd}\"}";
|
||||
Properties cp = convertProps("GRP",
|
||||
"resCode",
|
||||
"resCode.40000", "TB_ERR_999"); // 99999 에 대한 매핑 없음
|
||||
setupMock("GRP", template, cp);
|
||||
|
||||
Object result = handler.generateNonStandardErrorResponseMessage(
|
||||
"GRP", "ADP", new Properties(), null,
|
||||
toEaiMessage(buildMsg("99999", "기타오류")));
|
||||
|
||||
assertEquals("{\"resCode\":\"99999\"}", result);
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("convert.fields 쉼표 구분 중 공백 포함해도 정상 처리")
|
||||
void fields_공백_포함_정상처리() throws Exception {
|
||||
String template = "{\"resCode\":\"${MSG.MAIN_MSG.outp_msg_cd}\",\"resMessage\":\"${MSG.MAIN_MSG.outp_msg_ctnt}\"}";
|
||||
Properties cp = convertProps("GRP",
|
||||
" resCode , resMessage ", // 공백 포함
|
||||
"resCode.40000", "TB_ERR_999",
|
||||
"resMessage.40000", "필수값 오류");
|
||||
setupMock("GRP", template, cp);
|
||||
|
||||
Object result = handler.generateNonStandardErrorResponseMessage(
|
||||
"GRP", "ADP", new Properties(), null,
|
||||
toEaiMessage(buildMsg("40000", "40000")));
|
||||
|
||||
assertEquals("{\"resCode\":\"TB_ERR_999\",\"resMessage\":\"필수값 오류\"}", result);
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("매핑에 없는 값은 default 키로 폴백 변환")
|
||||
void 매핑_없는_값_default_폴백() throws Exception {
|
||||
String template = "{\"resCode\":\"${MSG.MAIN_MSG.outp_msg_cd}\"}";
|
||||
Properties cp = convertProps("GRP",
|
||||
"resCode",
|
||||
"resCode.40000", "TB_ERR_999",
|
||||
"resCode.default", "TB_ERR_DEFAULT"); // 폴백
|
||||
setupMock("GRP", template, cp);
|
||||
|
||||
Object result = handler.generateNonStandardErrorResponseMessage(
|
||||
"GRP", "ADP", new Properties(), null,
|
||||
toEaiMessage(buildMsg("99999", ""))); // 99999 매핑 없음
|
||||
|
||||
assertEquals("{\"resCode\":\"TB_ERR_DEFAULT\"}", result);
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("매핑이 있으면 default 보다 우선 적용")
|
||||
void 매핑_존재시_default_미사용() throws Exception {
|
||||
String template = "{\"resCode\":\"${MSG.MAIN_MSG.outp_msg_cd}\"}";
|
||||
Properties cp = convertProps("GRP",
|
||||
"resCode",
|
||||
"resCode.40000", "TB_ERR_999",
|
||||
"resCode.default", "TB_ERR_DEFAULT");
|
||||
setupMock("GRP", template, cp);
|
||||
|
||||
Object result = handler.generateNonStandardErrorResponseMessage(
|
||||
"GRP", "ADP", new Properties(), null,
|
||||
toEaiMessage(buildMsg("40000", ""))); // 40000 매핑 존재
|
||||
|
||||
assertEquals("{\"resCode\":\"TB_ERR_999\"}", result);
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("매핑도 default 도 없으면 원본 유지")
|
||||
void 매핑_default_모두없으면_원본_유지() throws Exception {
|
||||
String template = "{\"resCode\":\"${MSG.MAIN_MSG.outp_msg_cd}\"}";
|
||||
Properties cp = convertProps("GRP",
|
||||
"resCode",
|
||||
"resCode.40000", "TB_ERR_999" // 99999 매핑 없음, default 도 없음
|
||||
);
|
||||
setupMock("GRP", template, cp);
|
||||
|
||||
Object result = handler.generateNonStandardErrorResponseMessage(
|
||||
"GRP", "ADP", new Properties(), null,
|
||||
toEaiMessage(buildMsg("99999", "")));
|
||||
|
||||
assertEquals("{\"resCode\":\"99999\"}", result);
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("여러 필드에서 일부는 매핑, 일부는 default 로 변환")
|
||||
void 여러_필드_매핑과_default_혼합() throws Exception {
|
||||
String template = "{\"resCode\":\"${MSG.MAIN_MSG.outp_msg_cd}\",\"resMessage\":\"${MSG.MAIN_MSG.outp_msg_ctnt}\"}";
|
||||
Properties cp = new Properties();
|
||||
cp.setProperty("GRP.convert.fields", "resCode,resMessage");
|
||||
cp.setProperty("GRP.resCode.40000", "TB_ERR_999"); // 정확 매핑
|
||||
cp.setProperty("GRP.resMessage.default", "기타 오류입니다."); // resMessage 는 default 만
|
||||
setupMock("GRP", template, cp);
|
||||
|
||||
Object result = handler.generateNonStandardErrorResponseMessage(
|
||||
"GRP", "ADP", new Properties(), null,
|
||||
toEaiMessage(buildMsg("40000", "Bad Request")));
|
||||
|
||||
assertEquals("{\"resCode\":\"TB_ERR_999\",\"resMessage\":\"기타 오류입니다.\"}", result);
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("여러 에러코드에 대한 각각 다른 매핑 적용")
|
||||
void 다른_에러코드_다른_매핑() throws Exception {
|
||||
String template = "{\"resCode\":\"${MSG.MAIN_MSG.outp_msg_cd}\"}";
|
||||
Properties cp = new Properties();
|
||||
cp.setProperty("GRP.convert.fields", "resCode");
|
||||
cp.setProperty("GRP.resCode.40000", "TB_ERR_999");
|
||||
cp.setProperty("GRP.resCode.50000", "TB_ERR_500");
|
||||
setupMock("GRP", template, cp);
|
||||
|
||||
// 40000 → TB_ERR_999
|
||||
Object result1 = handler.generateNonStandardErrorResponseMessage(
|
||||
"GRP", "ADP", new Properties(), null,
|
||||
toEaiMessage(buildMsg("40000", "")));
|
||||
assertEquals("{\"resCode\":\"TB_ERR_999\"}", result1);
|
||||
|
||||
// 50000 → TB_ERR_500
|
||||
Object result2 = handler.generateNonStandardErrorResponseMessage(
|
||||
"GRP", "ADP", new Properties(), null,
|
||||
toEaiMessage(buildMsg("50000", "")));
|
||||
assertEquals("{\"resCode\":\"TB_ERR_500\"}", result2);
|
||||
}
|
||||
}
|
||||
|
||||
// ================================================================
|
||||
// 중첩 경로(dot path) 필드 코드 변환
|
||||
// ================================================================
|
||||
|
||||
@Nested
|
||||
@DisplayName("중첩 경로(dot path) 필드 코드 변환")
|
||||
class NestedPathConvert {
|
||||
|
||||
@Test
|
||||
@DisplayName("1단계 중첩 경로 필드 변환 – result.code")
|
||||
void 한단계_중첩_경로_변환() throws Exception {
|
||||
// 템플릿이 중첩 JSON 을 생성하는 경우 → 변환 전 JSON 을 직접 구성
|
||||
// 부모 render 결과를 미리 알고 있으므로, 간단한 템플릿 + 고정값 활용
|
||||
String template = "{\"result\":{\"code\":\"${MSG.MAIN_MSG.outp_msg_cd}\"}}";
|
||||
Properties cp = convertProps("GRP",
|
||||
"result.code",
|
||||
"result.code.40000", "TB_ERR_999");
|
||||
setupMock("GRP", template, cp);
|
||||
|
||||
Object result = handler.generateNonStandardErrorResponseMessage(
|
||||
"GRP", "ADP", new Properties(), null,
|
||||
toEaiMessage(buildMsg("40000", "")));
|
||||
|
||||
assertEquals("{\"result\":{\"code\":\"TB_ERR_999\"}}", result);
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("2단계 중첩 경로 필드 변환 – a.b.code")
|
||||
void 두단계_중첩_경로_변환() throws Exception {
|
||||
// 부모가 반환할 JSON: 고정 문자열 + stdmsg 치환 없이 직접 지정
|
||||
// 어댑터 그룹명 키 + template 이 fixed JSON 을 반환하도록 설정
|
||||
String fixedJson = "{\"a\":{\"b\":{\"code\":\"ERR_001\"}}}";
|
||||
PropManager mockProp = Mockito.mock(PropManager.class);
|
||||
Mockito.when(mockProp.getProperty(
|
||||
eq(TemplateAdapterErrorMsgHandler.PROP_GROUP),
|
||||
eq("GRP.template"))).thenReturn(fixedJson); // 변수 없는 고정 JSON
|
||||
Properties cp = convertProps("GRP",
|
||||
"a.b.code",
|
||||
"a.b.code.ERR_001", "MAPPED_CODE");
|
||||
Mockito.when(mockProp.getProperties(
|
||||
eq(TemplateCodeConvertAdapterErrorMsgHandler.PROP_GROUP))).thenReturn(cp);
|
||||
injectMockPropManager(mockProp);
|
||||
|
||||
Object result = handler.generateNonStandardErrorResponseMessage(
|
||||
"GRP", "ADP", new Properties(), null,
|
||||
toEaiMessage(buildMsg("", "")));
|
||||
|
||||
assertEquals("{\"a\":{\"b\":{\"code\":\"MAPPED_CODE\"}}}", result);
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("중첩 경로가 존재하지 않으면 해당 필드 변환 건너뜀")
|
||||
void 없는_중첩_경로_건너뜀() throws Exception {
|
||||
String template = "{\"resCode\":\"${MSG.MAIN_MSG.outp_msg_cd}\"}";
|
||||
Properties cp = convertProps("GRP",
|
||||
"nonExist.code", // JSON 에 없는 경로
|
||||
"nonExist.code.40000", "MAPPED");
|
||||
setupMock("GRP", template, cp);
|
||||
|
||||
Object result = handler.generateNonStandardErrorResponseMessage(
|
||||
"GRP", "ADP", new Properties(), null,
|
||||
toEaiMessage(buildMsg("40000", "")));
|
||||
|
||||
// 변환 대상 필드가 없으므로 원본 그대로
|
||||
assertEquals("{\"resCode\":\"40000\"}", result);
|
||||
}
|
||||
}
|
||||
|
||||
// ================================================================
|
||||
// 복합 시나리오
|
||||
// ================================================================
|
||||
|
||||
@Nested
|
||||
@DisplayName("복합 시나리오")
|
||||
class Combined {
|
||||
|
||||
@Test
|
||||
@DisplayName("일부 필드만 매핑 존재 – 나머지는 원본 유지")
|
||||
void 일부_필드_매핑_나머지_원본() throws Exception {
|
||||
String template = "{\"resCode\":\"${MSG.MAIN_MSG.outp_msg_cd}\",\"resMessage\":\"${MSG.MAIN_MSG.outp_msg_ctnt}\"}";
|
||||
Properties cp = convertProps("GRP",
|
||||
"resCode,resMessage",
|
||||
"resCode.40000", "TB_ERR_999"
|
||||
// resMessage 매핑 없음
|
||||
);
|
||||
setupMock("GRP", template, cp);
|
||||
|
||||
Object result = handler.generateNonStandardErrorResponseMessage(
|
||||
"GRP", "ADP", new Properties(), null,
|
||||
toEaiMessage(buildMsg("40000", "Bad Request")));
|
||||
|
||||
// resCode 는 변환, resMessage 는 원본 유지
|
||||
assertEquals("{\"resCode\":\"TB_ERR_999\",\"resMessage\":\"Bad Request\"}", result);
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("프로퍼티 그룹명 검증 – PROP_GROUP 상수 값")
|
||||
void PROP_GROUP_상수_검증() {
|
||||
assertEquals("AdapterErrorMessageHandler{CODE_CONVERT}",
|
||||
TemplateCodeConvertAdapterErrorMsgHandler.PROP_GROUP);
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("부모 PROP_GROUP 과 자식 PROP_GROUP 이 다른 그룹을 사용")
|
||||
void 부모_자식_PROP_GROUP_다름() {
|
||||
// 부모: "AdapterErrorMessageHandler"
|
||||
// 자식: "AdapterErrorMessageHandler{CODE_CONVERT}"
|
||||
assertNotEquals(
|
||||
TemplateAdapterErrorMsgHandler.PROP_GROUP,
|
||||
TemplateCodeConvertAdapterErrorMsgHandler.PROP_GROUP);
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("변환 후에도 JSON 에 변환 대상 외 필드는 그대로 유지")
|
||||
void 변환_후_비대상_필드_유지() throws Exception {
|
||||
String template = "{\"resCode\":\"${MSG.MAIN_MSG.outp_msg_cd}\",\"extra\":\"value\",\"resMessage\":\"${MSG.MAIN_MSG.outp_msg_ctnt}\"}";
|
||||
Properties cp = convertProps("GRP",
|
||||
"resCode",
|
||||
"resCode.40000", "TB_ERR_999");
|
||||
setupMock("GRP", template, cp);
|
||||
|
||||
Object result = handler.generateNonStandardErrorResponseMessage(
|
||||
"GRP", "ADP", new Properties(), null,
|
||||
toEaiMessage(buildMsg("40000", "오류")));
|
||||
|
||||
assertEquals("{\"resCode\":\"TB_ERR_999\",\"extra\":\"value\",\"resMessage\":\"오류\"}", result);
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("convert.fields 에 등록된 필드가 JSON 루트에 없어도 예외 없이 처리")
|
||||
void JSON에_없는_필드_등록시_예외_없음() throws Exception {
|
||||
String template = "{\"resCode\":\"${MSG.MAIN_MSG.outp_msg_cd}\"}";
|
||||
Properties cp = convertProps("GRP",
|
||||
"resCode,nonExistField",
|
||||
"resCode.40000", "TB_ERR_999",
|
||||
"nonExistField.40000", "MAPPED");
|
||||
setupMock("GRP", template, cp);
|
||||
|
||||
Object result = handler.generateNonStandardErrorResponseMessage(
|
||||
"GRP", "ADP", new Properties(), null,
|
||||
toEaiMessage(buildMsg("40000", "")));
|
||||
|
||||
// nonExistField 는 getJsonValue 가 null 반환 → 건너뜀, 예외 없음
|
||||
assertEquals("{\"resCode\":\"TB_ERR_999\"}", result);
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("inboundAdapterGroupName 이 달라지면 다른 convert.fields 키를 사용")
|
||||
void 다른_어댑터그룹_다른_키_사용() throws Exception {
|
||||
String template = "{\"resCode\":\"${MSG.MAIN_MSG.outp_msg_cd}\"}";
|
||||
Properties cp = new Properties();
|
||||
cp.setProperty("GROUP_A.convert.fields", "resCode");
|
||||
cp.setProperty("GROUP_A.resCode.40000", "A_MAPPED");
|
||||
cp.setProperty("GROUP_B.convert.fields", "resCode");
|
||||
cp.setProperty("GROUP_B.resCode.40000", "B_MAPPED");
|
||||
PropManager mockProp = Mockito.mock(PropManager.class);
|
||||
Mockito.when(mockProp.getProperty(
|
||||
eq(TemplateAdapterErrorMsgHandler.PROP_GROUP),
|
||||
anyString())).thenReturn(template);
|
||||
Mockito.when(mockProp.getProperties(
|
||||
eq(TemplateCodeConvertAdapterErrorMsgHandler.PROP_GROUP))).thenReturn(cp);
|
||||
injectMockPropManager(mockProp);
|
||||
|
||||
EAIMessage msg = toEaiMessage(buildMsg("40000", ""));
|
||||
|
||||
Object resultA = handler.generateNonStandardErrorResponseMessage(
|
||||
"GROUP_A", "ADP", new Properties(), null, msg);
|
||||
Object resultB = handler.generateNonStandardErrorResponseMessage(
|
||||
"GROUP_B", "ADP", new Properties(), null, msg);
|
||||
|
||||
assertEquals("{\"resCode\":\"A_MAPPED\"}", resultA);
|
||||
assertEquals("{\"resCode\":\"B_MAPPED\"}", resultB);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user