[
https://issues.apache.org/jira/browse/WW-5641?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel
]
Lukasz Lenart updated WW-5641:
------------------------------
Description:
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}}.
was:
* 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}}.
> 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
> Priority: Major
> Fix For: 7.3.0
>
>
> 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)