--- kind: CASE slug: messaging-runtime-core-f03 title: 선언된 content type과 실제 인코딩이 조용히 갈라질 수 있다 topic: schema-and-data-contracts project: clean-architecture-backend-template status: 게시 전 sourceRevision: 21234e38cdb9a926cbc92bb97a2aee2e4a7d2916 rootTreeNode: case:messaging-runtime-core-f03 evidenceCapturedOn: 2026-09-01 assets: - key: messaging-runtime-core-f03 file: ../../../final/evidence/rendered/messaging-runtime-core-f03.svg evidence: - ../../../final/evidence/raw/messaging-runtime-core-f03.txt source: - 원본 분석 절은 final/document.md#a19-messaging-runtime-core#L727 이다. module: messaging-runtime-core priority: P3 --- # 선언된 content type과 실제 인코딩이 조용히 갈라질 수 있다 encode가 codecs.find(message.contentType()).orElseGet(codecs::defaultCodec)으로 폴백한다. 출하 registry에는 JSON codec 하나만 등록된다. ## 관계 - **만들어 두고 흘리지 않는 진단값은 진단이 아니다** 같은 분석 리프에서 끌어낸 규칙이다. - **증가한다고 문서화한 값이 리터럴이면 그 사실을 적는다** 같은 분석 리프에서 끌어낸 규칙이다. - **안정 코드는 운영자의 행동이 갈리는 지점마다 나눈다** 같은 분석 리프에서 끌어낸 규칙이다. - **`CompletionStage`를 반환하는 메서드는 동기적으로 던지지 않는다** 같은 분석 리프에서 끌어낸 규칙이다. ## 문제 encode가 codecs.find(message.contentType()).orElseGet(codecs::defaultCodec)으로 폴백한다. 출하 registry에는 JSON codec 하나만 등록된다. ## 결론 봉투가 application/avro를 선언해도 JSON으로 인코딩되고, EncodedMessage의 content type은 codec이 정하므로 application/json이 된다. 실패하지 않고 다른 포맷으로 성공한다. 소비 측이 봉투의 원래 선언을 믿고 디코더를 고르면 어긋난다. DestinationProfile.schema().codec()이 목적지의 codec을 선언하는데 그 값과 대조하는 코드가 이 경로에 없다. ## 검증 환경 OpenJDK : 21.0.12 java -version 으로 확인 Gradle : 9.0.0 src/gradle/wrapper/gradle-wrapper.properties 의 distributionUrl 로 확인 확인 방식 : encode 의 폴백 코드와 출하 registry 에 등록되는 codec 목록 대조 소스 수정 : x ## 재현 조건 원문은 final/document.md#a19-messaging-runtime-core#L727 에 있다. ## 본문 `encode`가 `codecs.find(message.contentType()).orElseGet(codecs::defaultCodec)`으로 폴백한다. 출하 registry에는 JSON codec 하나만 등록된다. ## encode 의 폴백과 출하 registry :::evidence key="messaging-runtime-core-f03" alt="분석 문서 final/document.md#a19-messaging-runtime-core 에서 이 기록의 근거 절을 그대로 잘라낸 15줄. 코드베이스를 측정한 것이 아니라 원본 판정이 무엇을 적었는지를 보여 준다." caption="final/document.md#a19-messaging-runtime-core 발췌 — 15줄" zoom="true" ::: ## 실패하지 않고 다른 포맷으로 성공한다 봉투가 `application/avro`를 선언해도 JSON으로 인코딩되고, `EncodedMessage`의 content type은 codec이 정하므로 `application/json`이 된다. ## 소비 측이 원래 선언을 믿으면 어긋난다 `DestinationProfile.schema().codec()`이 목적지의 codec을 선언하는데 그 값과 대조하는 코드가 이 경로에 없다. ## 확인하지 못한 것 실제 브로커로 선언과 다른 포맷이 나가는 것을 관측하지 않았다. 폴백 코드와 등록 목록의 대조로 판정했다.