Skip to content

Apply charset preprocessing to Mono JSON decoding - #37217

Closed
blackdurumi wants to merge 1 commit into
spring-projects:mainfrom
blackdurumi:fix/37195-jackson2-mono-charset
Closed

Apply charset preprocessing to Mono JSON decoding#37217
blackdurumi wants to merge 1 commit into
spring-projects:mainfrom
blackdurumi:fix/37195-jackson2-mono-charset

Conversation

@blackdurumi

Copy link
Copy Markdown
Contributor

Fixes #37195

Problem

Jackson2JsonDecoder already preprocesses non-UTF-8 input for streaming decoding because Jackson's asynchronous parser only accepts UTF-8 (or ASCII). However, decodeToMono joined the original DataBuffer input and passed it directly to Jackson, bypassing that preprocessing.

As a result, a BOM-free ISO-8859-1 JSON payload could be decoded successfully through the streaming path but fail through the Mono path.

Solution

  • Apply the existing processInput hook before DataBufferUtils.join in decodeToMono.
  • Keep the existing aggregation limit, context handling, and decode(DataBuffer, ...) behavior unchanged.

This makes the Mono and streaming paths use the same charset handling.

Tests

The regression test uses BOM-free ISO-8859-1 JSON split across two data buffers and verifies that decodeToMono returns the expected values.

Verified with:

  • JAVA_HOME=/opt/homebrew/opt/openjdk@25 ./gradlew :spring-web:test --tests org.springframework.http.codec.json.Jackson2JsonDecoderTests
  • JAVA_HOME=/opt/homebrew/opt/openjdk@25 ./gradlew :spring-web:check
  • JAVA_HOME=/opt/homebrew/opt/openjdk@25 ./gradlew build
  • JAVA_HOME=/opt/homebrew/opt/openjdk@25 ./gradlew :spring-webflux:test --tests org.springframework.web.reactive.result.method.annotation.RequestMappingMessageConversionIntegrationTests.personResponseBodyWithObservable
The Jackson 2 decoder already preprocesses non-UTF-8 input for streaming decoding, but decodeToMono bypassed the processInput hook and passed raw buffers to Jackson. Applying the same preprocessing before aggregation keeps Mono and streaming decoding behavior consistent.

Constraint: Preserve the existing protected processInput extension point and the configured DataBuffer aggregation limit.
Rejected: Decode the joined buffer directly | That leaves non-UTF-8 Mono payloads without the charset normalization already used by the streaming path.
Confidence: high
Scope-risk: narrow
Directive: Keep processInput applied before aggregation whenever Mono decoding shares the Jackson 2 input path.
Tested: Jackson2JsonDecoderTests; spring-web:check; full ./gradlew build; targeted Jetty integration test rerun.
Not-tested: No known verification gaps.
Signed-off-by: jungh8n <jh981113@naver.com>
@spring-projects-issues spring-projects-issues added the status: waiting-for-triage An issue we've not yet triaged or decided on label Aug 31, 2026
@bclozel bclozel added the in: web Issues in web modules (web, webmvc, webflux, websocket) label Aug 31, 2026
@blackdurumi

Copy link
Copy Markdown
Contributor Author

I submitted this PR before confirming whether a contribution would be welcome. Based on the maintainer guidance, I’m closing it for now and will wait for the issue to be triaged. I’d be happy to revisit it if a PR is requested.

@bclozel bclozel added status: declined A suggestion or change that we don't feel we should currently apply and removed status: waiting-for-triage An issue we've not yet triaged or decided on labels Aug 31, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

in: web Issues in web modules (web, webmvc, webflux, websocket) status: declined A suggestion or change that we don't feel we should currently apply

3 participants