Skip to content

Fix property key serializer leaking into nested maps (#2050) - #6267

Open
CCCLL wants to merge 1 commit into
FasterXML:3.xfrom
CCCLL:fix-2050-map-key-serializer-scope
Open

CCCLL wants to merge 1 commit into
FasterXML:3.xfrom
CCCLL:fix-2050-map-key-serializer-scope

Conversation

@CCCLL

@CCCLL CCCLL commented Oct 3, 2026

Copy link
Copy Markdown

Fixes #2050.

When a property uses @JsonSerialize(keyUsing = ...), a Map contained in that Map's values currently reads the same property annotation again. This can pass an inner String key to a serializer for an outer custom key type and throw ClassCastException, or silently rewrite inner keys when the key types happen to match.

This change gives Map contents a private BeanProperty view after the enclosing Map has consumed the property's key serializer. Nested Map serializers recognize that view and skip reapplying the property-level key override. The view delegates the other property metadata so that sorting, inclusion rules, and contextual value serializers retain their configuration. Nested maps still use their own class-level or module-provided key serializers.

The content-converter recursion guard compares properties by identity. A small protected helper in StdSerializer lets MapSerializer check the original property before switching to the content view, preserving converters on enclosing Optional, List, and AtomicReference properties that produce a Map.

The scope is property-level keyUsing propagation into Map values; this does not introduce a general annotation-scoping API for all container serializers. The private property view and its interaction with contextual serializers are the main design points for review.

Validation:

  • 26 focused cases cover the original reproducer, same-type keys, static and dynamic typing, nested containers, converters, property metadata, class/module overrides, and cache warm-up order.
  • The same cases on the unchanged upstream baseline yield 10 passes, 6 assertion failures, and 10 errors. The enclosing-container converter cases pass on that baseline and with this change.
  • clean verify passes on JDK 17, 21, and 25: 7,468 tests on each, with 0 failures, 0 errors, and 1 skipped test.
  • animal-sniffer:check passes on JDK 17 against the Android API 34 signature.

For the local full builds, Mockito was loaded explicitly with -javaagent because dynamic attachment is unavailable on this host; the repository's POM and CI configuration are unchanged.

@gitar-bot

gitar-bot Bot commented Oct 3, 2026

Copy link
Copy Markdown
Code Review ✅ Approved

🟡 Medium risk · Changes scope of property-level key serializers across nested Map values.

Fixes property key serializer leaking into nested maps by giving Map contents a private BeanProperty view after the enclosing Map consumes the property's key serializer, preventing ClassCastException and silent key rewrites. Nested maps recognize this view and skip reapplying property-level key overrides while retaining sorting, inclusion rules, and contextual value serializers. Comprehensive test coverage (26 focused cases) and full test suite validation (7,468 tests) confirm the fix works correctly. No issues found.

Review coverage

📋 Rules No rules evaluated

🧪 Functional validation Not enabled · Set up

Options

Auto-apply is off → Gitar will not commit updates to this branch.
Display: compact → Counting what did not apply, without listing it.

Comment with these commands to change the behavior for this request:

Auto-apply Compact
gitar auto-apply:on         
gitar display:verbose         

Was this helpful? React with 👍 / 👎 | Powered by Gitar — free for open source

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

JsonSerialize.keyUsing propagates in values of the Map

1 participant