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

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

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

   Fixes [WW-5709](https://issues.apache.org/jira/browse/WW-5709)
   
   `java.beans.Introspector` only records a write method for a `void` setter, 
while OGNL binds through any public one-argument `setX` method regardless of 
its return type. `StrutsParameterAuthorizer` derived its view of what a target 
can take from `PropertyDescriptor.getWriteMethod()`, so a fluent setter was 
invisible to it:
   
   1. `@StrutsParameter` on a fluent setter never counted — the parameter was 
rejected unless the backing field was annotated too.
   2. On a `ModelDriven` action, an unannotated fluent setter on the *action* 
looked declared on neither the model nor the action and took the 
custom-accessor fallback WW-5698 left for Map-backed models, so it bound.
   
   ### Change
   
   `findBindableAccessor` resolves the depth-0 accessor the way OGNL does — 
from the already-cached `BeanInfo`'s method descriptors, by name and arity, 
public and non-static — and both `declaresProperty` and 
`hasValidAnnotatedMember` go through it. Depth ≥ 1 still uses the read method, 
so `OgnlParameterAllowlister` is untouched.
   
   Where several setters qualify, the most-derived declaration wins (an 
annotated override of a generic base's erased `setModel(Object)` is the one 
judged), and among overloads at that level an annotated one (a convenience 
`setAge(int)` beside `@StrutsParameter setAge(String)` no longer turns the 
property away — that would have been a regression against `main`).
   
   `hasValidAnnotatedPropertyDescriptor` is kept as a delegating shim, 
`@Deprecated(forRemoval = true)`; removal is 
[WW-5739](https://issues.apache.org/jira/browse/WW-5739) at 8.0.0.
   
   ### Behaviour change
   
   With `struts.parameters.requireAnnotations=true`: annotated fluent setters 
now bind; an unannotated fluent setter on a `ModelDriven` action is now 
rejected like a void one. Relative to 7.3.0 this is part of the WW-5698 change 
and rides on its migration note.
   
   ### Tests
   
   - `ParameterAuthorizerTest`: annotated / unannotated fluent setter, fluent 
setter on a `ModelDriven` action (rejected unannotated, authorized annotated), 
fluent setter on the model shadowing an unannotated action setter, static 
`setX` namesake (still no exemption — proven load-bearing), generic-override 
and same-class-overload preference.
   - 
`ParametersInterceptorTest.testModelDrivenFluentSetterOnActionRequiresAnnotation`:
 end-to-end through the real OGNL stack; RED on `main` (`secret` bound through 
the fluent setter), paired with two positive binds so the negative is not 
vacuous.
   
   `core`, `plugins/json`, `plugins/rest` test suites pass.
   
   🤖 Generated with [Claude Code](https://claude.com/claude-code)




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

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

> @StrutsParameter enforcement does not recognise fluent (non-void) setters
> -------------------------------------------------------------------------
>
>                 Key: WW-5709
>                 URL: https://issues.apache.org/jira/browse/WW-5709
>             Project: Struts 2
>          Issue Type: Task
>          Components: Core
>            Reporter: Lukasz Lenart
>            Priority: Major
>             Fix For: 7.4.0
>
>          Time Spent: 10m
>  Remaining Estimate: 0h
>
> {{java.beans.Introspector}} treats a {{set*}} method as a property write 
> method only when its return type is {{void}}. OGNL does not: 
> {{OgnlRuntime._getSetMethod}} matches a setter on name and argument count 
> alone, with no return-type check.
> {{StrutsParameterAuthorizer}} derives its view of what a target can bind from 
> {{java.beans}} property descriptors, so a fluent setter such as
>     public MyAction setFoo(String foo) { this.foo = foo; return this; }
> is invisible to the authorizer while remaining perfectly bindable by OGNL. 
> Two symptoms follow from that one cause.
> h3. 1. {{@StrutsParameter}} on a fluent setter has no effect
> {{hasValidAnnotatedPropertyDescriptor}} reads {{propDesc.getWriteMethod()}}, 
> which is {{null}} here, so it returns {{false}} and the check falls through 
> to {{hasValidAnnotatedField}}. Unless the backing field also carries the 
> annotation, the parameter is rejected even though the developer annotated the 
> setter. This fails closed, but it is silent and hard to diagnose.
> h3. 2. On a ModelDriven action, an unannotated fluent setter on the action 
> escapes the requirement
> {{declaresProperty}}, added in WW-5698, asks the same {{java.beans}} question 
> to decide whether a property belongs to the model or to the action. A fluent 
> setter on the action answers "neither", so the parameter takes the "declared 
> on neither the model nor the action" fallback that exists for custom OGNL 
> property accessors, and is exempted. OGNL then binds it through the fluent 
> setter on the action.
> This is not a regression: before WW-5698 every parameter on a ModelDriven 
> action was exempt unconditionally, so it is no more permissive than the 
> previous behaviour. It is the one case where WW-5698 does not fully reach its 
> stated goal of subjecting a ModelDriven action's own members to the 
> annotation requirement.
> h3. Suggested fix
> Identify setters the way OGNL does — by name and arity rather than by 
> {{java.beans}} write methods — in both 
> {{StrutsParameterAuthorizer.declaresProperty}} and 
> {{hasValidAnnotatedPropertyDescriptor}}, so the authorizer's model of what is 
> bindable matches what OGNL will actually bind.
> Found while reviewing WW-5698 / PR 
> [#1872|https://github.com/apache/struts/pull/1872].



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

Reply via email to