[ 
https://issues.apache.org/jira/browse/WW-5748?focusedWorklogId=1041697&page=com.atlassian.jira.plugin.system.issuetabpanels:worklog-tabpanel#worklog-1041697
 ]

ASF GitHub Bot logged work on WW-5748:
--------------------------------------

                Author: ASF GitHub Bot
            Created on: 15/Sep/26 14:40
            Start Date: 15/Sep/26 14:40
    Worklog Time Spent: 10m 
      Work Description: lukaszlenart opened a new pull request, #1947:
URL: https://github.com/apache/struts/pull/1947

   Fixes [WW-5748](https://issues.apache.org/jira/browse/WW-5748)
   
   ## Problem
   
   `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 in 7.2.0.
   
   ## Change
   
   - The handler 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. Same 
`XmlFactory` defaults (external entities and DTD support off) as the default 
constructor. 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 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. 
The wrapper only stays around a bean that has an unwrapped list, so the test 
bean carries both.
   - `jackson-dataformat-xml` is optional for the plugin: the class naming its 
wrapper (`XmlWrapperSupport.Xml`) is loaded only once `Class.forName` has 
confirmed it is present; the JSON path never reaches it.
   
   ## Tests
   
   `JacksonXmlHandlerTest` (existing class, extended): unwrapped list without a 
context, authorized, rejected; `@JacksonXmlText` with an element sibling; sole 
text with an attribute (Jackson XML's text deserializer, also newly reachable) 
read and authorized; per-property bean-typed `@JsonIdentityInfo` on a bean with 
an unwrapped list, authorized under `child.id.k`. The two XML any-setter tests 
in `ParameterAuthorizingModuleTest` now 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, the `null`-property 
re-contextualization, the optional-dependency guard under a class loader 
without the XML jar, `XmlFactory` defaults): nothing newly introduced.
   
   🤖 Generated with [Claude Code](https://claude.com/claude-code)




Issue Time Tracking
-------------------

            Worklog Id:     (was: 1041697)
    Remaining Estimate: 0h
            Time Spent: 10m

> Registering ParameterAuthorizingModule breaks unwrapped XML lists in 
> JacksonXmlHandler
> --------------------------------------------------------------------------------------
>
>                 Key: WW-5748
>                 URL: https://issues.apache.org/jira/browse/WW-5748
>             Project: Struts 2
>          Issue Type: Bug
>          Components: Plugin - REST
>            Reporter: Lukasz Lenart
>            Assignee: Lukasz Lenart
>            Priority: Major
>             Fix For: 7.4.0
>
>          Time Spent: 10m
>  Remaining Estimate: 0h
>
> h2. Summary
> {{JacksonXmlHandler}} registers {{ParameterAuthorizingModule}} on its 
> {{XmlMapper}}. {{ObjectMapper.registerModule}} inserts a module's 
> {{BeanDeserializerModifier}} at the _head_ of the modifier list, so the 
> Struts modifier runs before Jackson XML's own 
> {{XmlBeanDeserializerModifier}}. The Struts modifier wraps every bean 
> deserializer in {{RedactionAwareDeserializer}} (a 
> {{DelegatingDeserializer}}); the XML modifier then tests the deserializer it 
> receives with {{instanceof BeanDeserializerBase}}, does not recognise the 
> wrapper, and skips installing its {{WrapperHandlingDeserializer}}. 
> Unwrapped-list handling is therefore lost for every bean read through the XML 
> handler.
> h2. Current behaviour
> Reproduced with a plain {{XmlMapper}} (no authorization context bound — the 
> module's mere registration is enough):
> {code:java}public class Bean {
>     @JacksonXmlElementWrapper(useWrapping = false)
>     public List<String> items;
>     public String name;
> }
> {code}
> {code:xml}<Bean><items>a</items><items>b</items><name>n</name></Bean>
> {code}
> Without the module: {{items = [a, b]}}, {{name = n}}. With the module 
> registered: {{MismatchedInputException: Cannot construct instance of 
> java.util.ArrayList ... no String-argument constructor/factory method to 
> deserialize from String value ('a')}}. {{@JacksonXmlText}} is unaffected 
> (verified).
> Present since the module was introduced (7.2.0); independent of 
> {{struts.parameters.requireAnnotations}}.
> h2. Proposed change
> Let the XML module's modifier see a {{BeanDeserializerBase}}. Options, in 
> order of preference:
> * in {{ParameterAuthorizingModule.setupModule}}, or in {{JacksonXmlHandler}}, 
> register the modifier so that it runs _after_ the format module's (e.g. 
> construct the handler's mapper with the XML module first and add the Struts 
> modifier through {{SimpleModule.setDeserializerModifier}} on a module 
> registered last — verify the resulting order, since {{insertInListNoDup}} 
> prepends);
> * or have {{RedactionAwareDeserializer}} be applied from a later hook than 
> {{modifyDeserializer}}.
> Add a test on {{JacksonXmlHandler}} with an unwrapped list, with and without 
> an authorization context.
> h2. Compatibility notes
> No configuration or API change; only restores documented Jackson XML 
> behaviour for the REST plugin's XML handler.



--
This message was sent by Atlassian Jira
(v8.20.10#820010)

Reply via email to