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
standard-layout-djb.csv 의 DATA 가 GROUP(3)으로 선언돼 있어, 매핑설정의
BIZ_DATA=DATA[0].BIZ_DATA 인덱스 접근이 실패했다. getBizDataBytes() 가 null 을
반환하고 makeupDataScopLen 이 이를 그대로 역참조해 NPE 가 나면서
coordinateBeforeRequest/Response 가 통째로 실패, 관련 테스트 9건이 깨져 있었다.
운영 레이아웃(DB)대로 GRID(4)로 정정한다. 이 CSV 는 layout.file.type=CSV 인
테스트 설정에서만 사용된다.
- DATA 픽스처를 실제 전문과 같은 배열 형태로 변경
- GRID 는 인덱스 없는 경로가 직렬화에 쓰이지 않는 템플릿을 가리키므로, 조회/단정
경로를 운영과 같은 DATA[0] 형태로 변경
- 상대 헤더가 표준을 어긴 오류응답(dman_rspn_dvcd=S) 회귀 테스트 2건 추가.
같은 전문에 있던 선행 0 숫자(00001)와 이스케이프되지 않은 개행/탭도 픽스처에 포함
알려진 별건: DATA 가 GRID 이므로 StandardMessageCoordinatorDJB.DATA_SCOP_LEN
("DATA.data_scop_len") 이 행이 아닌 템플릿에 기록되어 data_scop_len 이 재계산되지
않고 수신값이 그대로 나간다. JSON 경로에서는 영향이 없어 별도 건으로 둔다.
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에 싱글턴으로 캐시되어
재사용되므로 인스턴스 필드로 안전하게 캐시 가능