[
https://issues.apache.org/jira/browse/WW-5641?focusedWorklogId=1028298&page=com.atlassian.jira.plugin.system.issuetabpanels:worklog-tabpanel#worklog-1028298
]
ASF GitHub Bot logged work on WW-5641:
--------------------------------------
Author: ASF GitHub Bot
Created on: 06/Jul/26 17:36
Start Date: 06/Jul/26 17:36
Worklog Time Spent: 10m
Work Description: lukaszlenart opened a new pull request, #1766:
URL: https://github.com/apache/struts/pull/1766
Fixes [WW-5641](https://issues.apache.org/jira/browse/WW-5641)
## Problem
A custom JSON writer/reader configured the documented way is silently
ignored on the 7.2.x line — the framework always uses the default
`StrutsJSONWriter` / `StrutsJSONReader`:
```xml
<bean type="org.apache.struts2.json.JSONWriter" name="flexJSONWriter"
class="org.demo.FlexJSONWriter" scope="prototype"/>
<constant name="struts.json.writer" value="flexJSONWriter"/>
```
This worked on 7.1.x and regressed in 7.2.x. The extension point is still
documented at <https://struts.apache.org/plugins/json/>, so this is a
regression, not an intended API change.
## Root cause
Writer/reader selection moved from a **runtime, by-name lookup** (7.1.x) to
a **container-build-time alias** (7.2.x, introduced with the JSON hardening
rework that added `<bean-selection>` to the plugin's `struts-plugin.xml`).
`XmlDocConfigurationProvider.registerBeanSelection()` invokes
`JSONBeanSelectionProvider.register()` →
`AbstractBeanSelectionProvider.alias()` **inline, the moment the
`<bean-selection>` element is parsed** in the JSON plugin's
`struts-plugin.xml`. At that instant the shared `props` hold only the plugin's
own `struts.json.writer=struts`; the application `struts.xml` is a *later*
`ContainerProvider` whose override bean/constant have not been folded in yet.
So `alias()` locks `JSONWriter/DEFAULT_NAME → StrutsJSONWriter`, and nothing
re-runs the selection once the app config loads. `JSONUtil` in 7.2.x injected
that frozen default binding.
The 7.1.x code was immune because `JSONUtil` resolved the writer/reader by
the constant value at container-use time — after the full container (including
the app `struts.xml`) was built.
## Fix
Restore 7.1.x-style deferred resolution, confined to `JSONUtil`: inject the
`Container` and resolve the writer/reader from the **effective**
`struts.json.writer` / `struts.json.reader` constant values (named lookup) at
injection time, instead of relying on the build-time default alias.
`setWriter`/`setReader` remain public plain setters (only `@Inject` removed).
Preserves the 7.2.x hardening:
- `StrutsJSONWriter` / `StrutsJSONReader` remain the shipped defaults.
- JSON DoS limits (`maxDepth`, `maxElements`, `maxLength`,
`maxStringLength`, `maxKeyLength`) untouched — their `@Inject` setters still
fire on the resolved bean.
- `JSONUtil` and the writer/reader stay `prototype`; `serialize(...)` never
touches `container`, so per-instance resolution and thread-safety of the
bean-info cache are unchanged.
The `<bean-selection>` / default alias is left in place (harmless) so any
external `container.getInstance(JSONWriter.class)` keeps working.
## Test
`JSONWriterOverrideTest` boots the real `Dispatcher` config chain
(`struts-default.xml,struts-plugin.xml,struts-json-override.xml`, in that
order) so the provider ordering that causes the bug is reproduced, and asserts
the **effective** writer (serialize sentinel) and reader
(`getReader().getClass()`) — covering both `struts.json.writer` and
`struts.json.reader`. Verified failing before the fix, passing after. Full
`struts2-json-plugin` suite: 127/127 green.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Issue Time Tracking
-------------------
Worklog Id: (was: 1028298)
Remaining Estimate: 0h
Time Spent: 10m
> JSON plugin ignores struts.json.writer / struts.json.reader override
> (regression since 7.2.x)
> ---------------------------------------------------------------------------------------------
>
> Key: WW-5641
> URL: https://issues.apache.org/jira/browse/WW-5641
> Project: Struts 2
> Issue Type: Bug
> Components: Plugin - JSON
> Affects Versions: 7.2.1
> Reporter: Lukasz Lenart
> Assignee: Lukasz Lenart
> Priority: Major
> Fix For: 7.3.0
>
> Time Spent: 10m
> Remaining Estimate: 0h
>
> h2. Summary
> A custom JSON writer/reader configured the documented way via the
> {{struts.json.writer}} /
> {{struts.json.reader}} constants is silently ignored. The framework always
> uses the default
> {{StrutsJSONWriter}} / {{StrutsJSONReader}}. This worked in the 7.1.x line
> and regressed in
> 7.2.x as a side effect of the JSON hardening rework that introduced
> {{<bean-selection>}} for
> the JSON plugin.
> The extension point is still documented at
> [https://struts.apache.org/plugins/json/], so this
> is a regression, not an intended API change.
> h2. How to reproduce
> In an application {{struts.xml}}:
> {code:xml}
> <bean type="org.apache.struts2.json.JSONWriter" name="flexJSONWriter"
> class="org.demo.FlexJSONWriter" scope="prototype"/>
> <constant name="struts.json.writer" value="flexJSONWriter"/>
> {code}
> *Expected:* JSON is serialized by {{FlexJSONWriter}}.
> *Actual:* JSON is serialized by the default {{StrutsJSONWriter}}; the
> override is never used.
> Confirmed via the {{json-customize}} module reproduction in
> apache/struts-examples PR #535
> ({{ProduceActionTest}}): passes on 7.1.x, fails on 7.2.x.
> h2. Root cause
> Writer/reader selection moved from a *runtime, by-name lookup* to a
> *container-build-time alias*.
> * In 7.1.x, {{JSONUtil}} injected the {{Container}} and resolved the
> writer/reader at use time
> from the constant value — this ran after the full container (including the
> app {{struts.xml}})
> was built, so overrides applied.
> * In 7.2.x, {{JSONUtil}} injects the default {{JSONWriter}} / {{JSONReader}}
> binding, which is
> chosen once by the new {{JSONBeanSelectionProvider}} (wired via
> {{<bean-selection>}} in the
> plugin's {{struts-plugin.xml}}).
> {{XmlDocConfigurationProvider.registerBeanSelection()}} invokes the
> bean-selection provider
> *inline, the moment the {{<bean-selection>}} element is parsed* in the
> plugin's
> {{struts-plugin.xml}}. At that instant the shared {{props}} hold only the
> plugin's own
> {{struts.json.writer=struts}}; the application {{struts.xml}} is a later
> {{ContainerProvider}}
> whose override bean/constant have not been folded in yet. So
> {{AbstractBeanSelectionProvider.alias()}} takes the "found by default name"
> branch and locks
> {{JSONWriter/DEFAULT_NAME -> StrutsJSONWriter}}. Nothing re-runs the
> selection once the app
> config loads, so the override is dropped. The 7.1.x deferred runtime lookup
> was immune to this
> ordering.
> h2. Proposed fix
> Restore deferred, runtime by-name resolution in {{JSONUtil}} (mirrors 7.1.x):
> inject the
> {{Container}} and resolve the writer/reader from the *effective*
> {{struts.json.writer}} /
> {{struts.json.reader}} constant values at injection time, instead of relying
> on the
> build-time default alias.
> * Change is localized to {{JSONUtil}}; {{JSONUtil}} is the only consumer of
> {{JSONWriter}} /
> {{JSONReader}}.
> * Preserves the 7.2.x hardening: {{StrutsJSONWriter}} / {{StrutsJSONReader}}
> remain the shipped
> defaults, and the DoS limits ({{struts.json.maxDepth}}, {{maxElements}},
> {{maxLength}},
> {{maxStringLength}}, {{maxKeyLength}}) are unchanged.
> * Preserves {{prototype}} scope and per-instance resolution — no
> thread-safety regression for
> the stateful bean-info caching.
> h2. Regression test
> Add a test exercising the full bootstrap ({{struts-default.xml}} + the JSON
> plugin's
> {{struts-plugin.xml}} + a user override config, in that order) and assert the
> *effective*
> writer and reader used by {{JSONUtil}} are the overrides — covering both
> {{struts.json.writer}}
> and {{struts.json.reader}}.
--
This message was sent by Atlassian Jira
(v8.20.10#820010)