outp_msg_cd(NCMM00001) / outp_msg_ctnt(정상처리되었습니다.) 가 표준전문 레이아웃의
기본값으로 붙어 있어서, "아무도 채우지 않은 상태" 와 "정상이라고 판정한 상태" 가
값만으로 구분되지 않았다. 2026-09 사고에서 MSG 부 파싱이 통째로 스킵됐는데도
오류가 "정상처리되었습니다." 로 보고된 것이 이 때문이다.
레이아웃 기본값을 없애고, StandardMessageCoordinatorDJB.coordinateBeforeResponse 에서
정상 응답일 때만 채운다. 이 메서드는 모든 동기 응답이 거치는 마지막 관문이라
(RequestProcessor 에서 호출) 경로를 빠짐없이 덮는다.
두 조건을 함께 본다.
- 정상 응답(procs_rslt_dvcd=S) 일 때만. 오류 응답에 정상 메시지를 채우면 사고 재현이다.
- 값이 비어 있을 때만(setIfBlank). 대외계가 표준응답으로 보낸 MSG 가 우선이며
덮어쓰면 JsonReader 의 MSG 부 보존 수정이 무의미해진다.
테스트: 기존 3건이 coordinateAfterRecvNonStdSyncResponse 직후에 단정하고 있었으나
값은 이제 마지막 관문에서 채워지므로, 실제 흐름대로 coordinateBeforeResponse 까지
거치도록 고치고 단정도 "공백 아님" 에서 상수 일치로 강화했다.
설계 조건을 지키는 회귀 테스트 2건을 추가했다.
- 오류응답에는_정상메시지가_채워지지_않는다
- 대외계가_보낸_MSG_값은_덮어쓰지_않는다
주의: 이 CSV 는 layout.file.type=CSV 인 테스트 설정에서만 쓰인다. 운영은 DB 레이아웃을
읽으므로 DB 의 두 항목 기본값도 함께 비워야 실제 효과가 있다. 비우기 전까지는
setIfBlank 가 아무것도 하지 않아 기존과 동일하게 동작한다.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UnybKuxcuPafGhVGh4wqkZ
상대 응답에 이스케이프되지 않은 제어문자가 섞여 오면
"Illegal unquoted character ((CTRL-CHAR, code 10))" 로 실패한다.
readTree() 전에 JacksonUtil.escapeControlChars() 로 표준 JSON 으로 맞춘다.
검증: gradlew compileJava BUILD SUCCESSFUL
기본 ObjectMapper 는 JSON 숫자 왕복에서 값을 변형한다
(100000000.00 -> 1.0E8, 0.00000012 -> 1.2E-7). payload 를 다루는
지점을 JacksonUtil.newNumberSafeMapper() 로 맞춘다.
- KakaopayAdapterErrorMsgHandler: 응답 JSON 파싱/왕복 지점 전환
- HttpClient5AdapterServiceBigTechAddFilter: JsonNode 직렬화 지점 전환
- KakaopayFilter: JacksonUtil.readTree(message, OBJECT_MAPPER) 로 plain mapper 를
넘기고 있어 유틸을 써도 파싱이 깨졌다. 인자 1개 오버로드(number-safe 싱글턴)를
쓰도록 바꾸고 plain 필드 제거
- JsonPathExtractRequestMessage: 미사용으로 보였던 objectMapper 필드는 사실
연결이 빠진 것이었다. JsonPath 의 기본 JacksonJsonNodeJsonProvider() 가 내부적으로
plain ObjectMapper 를 쓰기 때문에 JSON 실수가 DoubleNode 로 파싱되어
resultNode.asText() 가 "1.0E8" 을 반환했다. 프로바이더에 number-safe mapper 를
주입해 해결
- NaverpayAdapterErrorMsgHandler: Kakaopay 판을 복사하며 딸려온 미사용 필드/import 제거.
이 핸들러는 JSON 을 파싱하지 않고 StandardMessage 로만 응답을 만든다
검증: gradlew compileJava BUILD SUCCESSFUL
- 하드코딩된 30초 만료를 제거하고 oAuthCredentialVo.getIntervalSec() 기준으로
복원 (미설정 시 24시간 폴백), 스케줄러 주기와 불일치하던 문제 해결
- execute() 호출마다 PoolingHttpClientConnectionManager/CloseableHttpClient를
새로 만들고 즉시 닫던 것을, mTLS 여부+clientId 조합별로 1회만 생성해 재사용하도록
변경. 이 서비스는 HttpClientAccessTokenServiceFactoryByDB에 싱글턴으로 캐시되어
재사용되므로 인스턴스 필드로 안전하게 캐시 가능
- coordinateAfterCreateMessageByRule에서 StandardItem의 refValue가
\${callProp.키} 패턴이면 Properties에서 값을 꺼내 setValue로 설정한다.
- \${callProp.키:기본값} 구문으로 기본값 지정 가능
- 점(.) 구분으로 Properties/Map 중첩 구조 탐색 지원
- GROUP 타입 재귀 순회, GRID/FARRAY는 건너뜀