Skip to content

Keep Builder.defaultUseWrapper() from modifying shared introspector - #913

Merged
cowtowncoder merged 8 commits into
FasterXML:3.xfrom
Sahana2524:default-use-wrapper-shared-introspector
Sep 23, 2026
Merged

cowtowncoder merged 8 commits into
FasterXML:3.xfrom
Sahana2524:default-use-wrapper-shared-introspector

Conversation

@Sahana2524

@Sahana2524 Sahana2524 commented Sep 18, 2026

Copy link
Copy Markdown
Contributor

defaultUseWrapper() on a rebuilt builder also reconfigures the original mapper

The builder applied the setting through setDefaultUseWrapper() on an introspector instance it shares with the mapper it came from via rebuild() (or one it already built), so mapper.rebuild().defaultUseWrapper(false).build() flips wrapping on the original too, XmlMapper.shared() included: types it has not cached yet are written unwrapped, and a wrapped document reads back as an empty list without any error.

Fix

The builder now never modifies the introspector in place, but swaps in a re-configured copy (the way nameForTextElement() already does for the factory):

  • XmlAnnotationIntrospector gets new mutant factory withDefaultUseWrapper(boolean) (since 3.3); default implementation returns this, for introspectors without the setting. Implementations must extend (and return) AnnotationIntrospector.
  • JacksonXmlAnnotationIntrospector implements it with a new protected copy constructor, JacksonXmlAnnotationIntrospector(JacksonXmlAnnotationIntrospector src, boolean defaultUseWrapper), which delegates to the JacksonAnnotationIntrospector copy constructor added in Add copy constructor for JacksonAnnotationIntrospector jackson-databind#6231 (so databind settings are copied as well).
  • XmlAnnotationIntrospector.Pair implements it by delegating to its primary and secondary introspectors, returning this if neither changes, so pair structure is retained.
  • XmlMapper.Builder.defaultUseWrapper() calls withDefaultUseWrapper() on its introspector, then verifies that no contained XML introspector still needs the change; builder is only modified once both succeed.
  • JacksonXmlAnnotationIntrospector.setDefaultUseWrapper() is deprecated in favor of withDefaultUseWrapper().
  • README.md: replaced stale reference to 2.x JacksonXmlModule.setDefaultUseWrapper() with XmlMapper.builder().defaultUseWrapper().

Behavior changes

Setting is always applied ("last call wins"). defaultUseWrapper() used to do nothing if the builder's own flag already had the given value, even if the introspector had since been replaced with one using a different setting (e.g. defaultUseWrapper(false), then annotationIntrospector(new JacksonXmlAnnotationIntrospector(true)), then defaultUseWrapper(false) again). It now always applies the setting to the introspector.

Fail fast where a copy cannot be made. Whenever an introspector would need a different setting, defaultUseWrapper() now throws IllegalStateException for:

  • a sub-class of JacksonXmlAnnotationIntrospector or XmlAnnotationIntrospector.Pair that does not override withDefaultUseWrapper() (checked with ClassUtil.verifyMustOverride(), same as ObjectMapper.copy()), instead of silently losing its type;
  • a databind AnnotationIntrospectorPair (at top level, or nested within XmlAnnotationIntrospector.Pair) containing an XML introspector that would need the change: it cannot be re-configured without changing its structure (and it does not dispatch XML-specific methods anyway); the message points to XmlAnnotationIntrospector.Pair.

Previously these cases "worked" by modifying the shared instance (or, with the builder flag unchanged, were silently ignored).

Tests

MapperCopyTest:

  • rebuilt mapper and previously built mapper keep wrapping;
  • custom sub-class type and paired JAXB introspector are retained;
  • setting is applied after introspector has been replaced;
  • non-overriding introspector sub-class, non-overriding Pair sub-class, and databind pair (top-level and nested) fail without modifying introspectors or builder.

@github-actions

Copy link
Copy Markdown

🧪 Code Coverage Report

Metric Coverage Change
Instructions coverage 75.76% 📈 +0.070%
Branches branches 70.08% 📈 +0.070%

Coverage data generated from JaCoCo test results

@github-actions

Copy link
Copy Markdown

🧪 Code Coverage Report

Metric Coverage Change
Instructions coverage 75.76% 📈 +0.070%
Branches branches 70.08% 📈 +0.070%

Coverage data generated from JaCoCo test results

@github-actions

Copy link
Copy Markdown

🧪 Code Coverage Report

Metric Coverage
Instructions coverage 77.50%
Branches branches 70.75%

Coverage data generated from JaCoCo test results

@github-actions

Copy link
Copy Markdown

🧪 Code Coverage Report

Metric Coverage Change
Instructions coverage 77.50% 📈 +0.060%
Branches branches 70.75% 📈 +0.070%

Coverage data generated from JaCoCo test results

@github-actions

Copy link
Copy Markdown

🧪 Code Coverage Report

Metric Coverage Change
Instructions coverage 77.65% 📈 +0.210%
Branches branches 70.68% 📈 +0.000%

Coverage data generated from JaCoCo test results

@github-actions

Copy link
Copy Markdown

🧪 Code Coverage Report

Metric Coverage Change
Instructions coverage 77.70% 📈 +0.260%
Branches branches 71.00% 📈 +0.320%

Coverage data generated from JaCoCo test results

@github-actions

Copy link
Copy Markdown

🧪 Code Coverage Report

Metric Coverage Change
Instructions coverage 77.69% 📈 +0.250%
Branches branches 71.00% 📈 +0.320%

Coverage data generated from JaCoCo test results

@github-actions

Copy link
Copy Markdown

🧪 Code Coverage Report

Metric Coverage Change
Instructions coverage 77.69% 📈 +0.250%
Branches branches 70.97% 📈 +0.290%

Coverage data generated from JaCoCo test results

@cowtowncoder

Copy link
Copy Markdown
Member

Changed a bit, will merge: thank you again @Sahana2524 !

@cowtowncoder
cowtowncoder merged commit aab92bd into FasterXML:3.x Sep 23, 2026
3 checks passed
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.

2 participants