Lukasz Lenart created WW-5660:
---------------------------------

             Summary: Define interceptor parameters via dedicated params 
classes instead of setters on the interceptor
                 Key: WW-5660
                 URL: https://issues.apache.org/jira/browse/WW-5660
             Project: Struts 2
          Issue Type: Improvement
          Components: Core Interceptors
            Reporter: Lukasz Lenart
             Fix For: 8.0.0


h3. Current state

Interceptor {{<param>}} values are applied by reflection onto the interceptor 
instance at
configuration-parse time:

{code:java}
// DefaultInterceptorFactory.java:86
reflectionProvider.setProperties(params, interceptor);
{code}

Every parameter an interceptor accepts is therefore a setter on the interceptor 
itself, and
configuration-time state and request-time state share one object. The scale 
in-tree today:

* 44 interceptor implementations across {{core}} and {{plugins}}
* 61 distinct {{public void setXxx(String)}} parameter setters in 
{{org.apache.struts2.interceptor}} alone
* {{disabled}} is universal, held as a shared {{boolean}} on 
{{AbstractInterceptor}} (field at
  {{:28}}, written by {{setDisabled}} at {{:56-58}}, read by 
{{shouldIntercept}} at {{:61-63}})

h3. Why this is worth changing

Interceptors are singletons: built once at configuration-parse time and reused 
for every
request, and shared across every action referencing the same stack. Nothing in 
the current
shape distinguishes a parameter that is fixed at configuration time from one 
that varies per
request, so the type system offers no protection against writing request-scoped 
state onto
process-wide state.

WW-5659 is the concrete demonstration. {{WithLazyParams}} resolved {{${...}}} 
parameters per
request and applied them to the interceptor through exactly the setters above, 
so concurrent
requests could observe one another's upload validation policy. The fix had to 
change the
contract so resolved values land in a per-invocation object rather than on the 
interceptor.

h3. What WW-5659 already established

WW-5659 introduced the vocabulary this issue would generalise, in
{{org.apache.struts2.interceptor}}:

* {{InterceptorParams}} - the general contract for a parameters holder
* {{DisableParams}} - opt-in holder state for the universal {{disabled}} 
parameter
* {{UploadPolicy}} - the file upload holder, {{extends DisableParams}}

It also began moving {{disabled}} off {{AbstractInterceptor}}: on the lazy path 
the singleton
field is no longer written, and the holder is authoritative.

h3. Proposal

Give every interceptor a dedicated parameters class rather than a set of 
setters:

* the framework populates the params object rather than the interceptor
* the interceptor consumes it, and holds no mutable parameter state itself
* configuration-time and request-time state become separable by construction
* {{disabled}} moves off {{AbstractInterceptor}} entirely and onto 
{{DisableParams}}

The natural population point already exists at 
{{DefaultInterceptorFactory.java:86}}, which
would target the params object instead of the interceptor.

h3. Why 8.0.0

This is an ecosystem-wide breaking change. It touches all 44 in-tree 
interceptors plus every
third-party interceptor that declares a {{<param>}}. It fits alongside the API 
reshaping
already targeted at 8.0.0 - see WW-4759 ({{struts2-api}} extraction).

h3. Explicitly not a correctness fix

No known bug depends on this. WW-5659 established that {{disabled}} was racy 
only on the lazy
parameter path, and that path is fixed. This issue is a design improvement that 
makes the
whole class of bug unexpressible rather than fixed case by case, so it should 
not inherit
WW-5659's urgency and should not be rushed into a minor release.

h3. Scope for a follow-up design

Worth deciding during design rather than up front:

* whether the params object is supplied by the interceptor (as 
{{WithLazyParams.newLazyParams()}}
  does) or resolved by the framework from a declared type
* how {{ConditionalInterceptor}} and {{MethodFilterInterceptor}} parameters fit
* whether a migration shim is offered for third-party interceptors, or whether 
the compile
  break is accepted as it was in WW-5659
* how much of the OGNL type conversion currently provided by reflection-based 
population must
  be preserved

h3. References

* WW-5659 - request-scoped resolution of lazy interceptor params; introduced
  {{InterceptorParams}}, {{DisableParams}}, {{UploadPolicy}}
* WW-4759 - struts2-api extraction, also targeted at 8.0.0




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

Reply via email to