WW-5748 fix(rest): let Jackson XML's deserializer modifier see the bean deserializer - #1947
Merged
Merged
Conversation
…an deserializer JacksonXmlHandler registered ParameterAuthorizingModule on an XmlMapper whose constructor had already registered JacksonXmlModule. A module's deserializer modifier is inserted at the head of the list, so the authorizing modifier ran first and handed Jackson XML's modifier a RedactionAwareDeserializer, which fails its instanceof BeanDeserializerBase test: the XML wrapper that reads an unwrapped list (@JacksonXmlElementWrapper(useWrapping = false)) was never installed, and every such list failed to deserialize through the XML handler, authorization context or not, since the module was introduced. The handler now builds the XmlMapper without a module and registers JacksonXmlModule after ParameterAuthorizingModule, so the XML modifier runs first and the authorizing wrapper goes around its result. The module's Javadoc states the order for handlers that register it themselves. With Jackson XML's wrapper now inside the authorizing one, the per-property @JsonIdentityInfo reader rebuild in RedactionAwareDeserializer.createContextual (WW-5746) walks the delegating wrappers down to the bean. Jackson XML's wrapper cannot take a new delegatee, so it is rebuilt around the bean and contextualized with a null property, which recomputes its unwrapped names without building the id reader over again; other delegating wrappers get the rebuilt bean through replaceDelegatee. The wrapper only stays around a bean that has an unwrapped list, so the combination is exercised by a bean carrying both. jackson-dataformat-xml is optional for the plugin, so the class naming its wrapper is loaded only once it is known to be present. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
lukaszlenart
force-pushed
the
WW-5748
branch
from
September 15, 2026 16:16
4a04f2a to
cb63fc5
Compare
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.



Fixes WW-5748
Problem
JacksonXmlHandlerregisteredParameterAuthorizingModuleon anXmlMapperwhose constructor had already registeredJacksonXmlModule. A module's deserializer modifier is inserted at the head of the list, so the authorizing modifier ran first and handed Jackson XML's modifier aRedactionAwareDeserializer, which fails itsinstanceof BeanDeserializerBasetest. The XML wrapper that reads an unwrapped list (@JacksonXmlElementWrapper(useWrapping = false)) was never installed, and every such list failed to deserialize through the XML handler — authorization context or not — since the module was introduced in 7.2.0.Change
XmlMapperwithout a module and registersJacksonXmlModuleafterParameterAuthorizingModule, so the XML modifier runs first and the authorizing wrapper goes around its result. SameXmlFactorydefaults (external entities and DTD support off) as the default constructor. The module's Javadoc states the order for handlers that register it themselves.@JsonIdentityInforeader rebuild inRedactionAwareDeserializer.createContextual(WW-5746) walks delegating wrappers down to the bean. Jackson XML's wrapper cannot take a new delegatee, so it is rebuilt around the bean and contextualized with anullproperty, which recomputes its unwrapped names without building the id reader over again. The wrapper only stays around a bean that has an unwrapped list, so the test bean carries both.jackson-dataformat-xmlis optional for the plugin: the class naming its wrapper (XmlWrapperSupport.Xml) is loaded only onceClass.forNamehas confirmed it is present; the JSON path never reaches it.Tests
JacksonXmlHandlerTest(existing class, extended): unwrapped list without a context, authorized, rejected;@JacksonXmlTextwith an element sibling; sole text with an attribute (Jackson XML's text deserializer, also newly reachable) read and authorized; per-property bean-typed@JsonIdentityInfoon a bean with an unwrapped list, authorized underchild.id.k. The two XML any-setter tests inParameterAuthorizingModuleTestnow build their mapper the way the handler does.mvn test -DskipAssembly -pl plugins/rest: 216 tests, 0 failures. One code-review pass and one security pass (module order vs. property wrapping, XML renames, resync under virtual wrapping, thenull-property re-contextualization, the optional-dependency guard under a class loader without the XML jar,XmlFactorydefaults): nothing newly introduced.🤖 Generated with Claude Code