Lukasz Lenart created WW-5849:
---------------------------------
Summary: Add a forward result: server-side transfer to an opted-in
action with an explicit hand-off
Key: WW-5849
URL: https://issues.apache.org/jira/browse/WW-5849
Project: Struts 2
Issue Type: New Feature
Components: Core, Core Interceptors, Plugin - Convention
Reporter: Lukasz Lenart
Fix For: 7.6.0
Action chaining (the {{chain}} result plus {{ChainingInterceptor}}) lets one
action hand off to another inside the same request, without a round-trip to the
browser. Users rely on that: the "Is anyone using action chaining?" thread on
user@ showed several applications that use it for server-side branching flows,
where the next action depends on the state of the current one.
Chaining also does much more than that hand-off needs:
* any action in any namespace can be chained to, and the target name is
evaluated as an expression against the value stack
* {{ChainingInterceptor}} copies every readable property of every object in the
value stack onto the target action, by name
* the source action stays in the value stack below the target
* the Convention plugin chains implicitly ({{foo}} returning {{bar}} →
{{foo-bar}})
This ticket adds a {{forward}} result that keeps the hand-off and makes both of
its boundaries explicit: which actions can be forwarded to, and what data
reaches them.
h2. Behaviour
# *Static target.* {{actionName}}, {{namespace}} and {{method}} are literal
values from configuration; branching uses result codes, one {{forward}} result
per branch.
# *Target-side allowlist.* An action can be forwarded to only if it opts in,
with a class-level annotation (not {{@Inherited}}) or an attribute on the
{{action}} element. Both are recorded on {{ActionConfig}}. Forwarding to an
action that has not opted in throws.
# *Fresh value stack and own {{ActionContext}}.* The source action is not in
the target's value stack; the target's result renders against the target only.
# *Request parameters are bound again*, like a servlet forward, under the
target's own {{@StrutsParameter}} rules.
# *Explicit hand-off, named on both sides.* The {{forward}} result lists the
values it passes (evaluated against the source action); the target marks the
properties that accept a forwarded value with a dedicated annotation, separate
from {{@StrutsParameter}}. Only values named on both sides are set. In this
version: top-level setters on the action only, no nested paths, no ModelDriven
model; a value that fails conversion is dropped and logged.
# *Hand-off is applied after {{params}}* by a dedicated interceptor added
directly after {{params}} in the shipped stacks ({{defaultStack}},
{{paramsPrepareParamsStack}}, REST and Bean Validation plugin stacks). A
forward that carries values to a target whose stack lacks the interceptor
throws.
# *Action errors, field errors and messages do not carry over* unless passed
explicitly.
# *Depth limit* per request (new constant, default 5) instead of name-based
loop detection; exceeding it throws {{StrutsException}}.
# *The target runs its full interceptor stack.*
# *Convention:* the implicit {{foo}} → {{foo-bar}} transfer becomes an implicit
forward, applied only when {{foo-bar}} has opted in. It carries no hand-off
values. {{@Result}} accepts {{type = "forward"}} and its params.
h2. Configuration
A new {{struts-7.6.dtd}} adds the opt-in attribute to the {{action}} element.
No other grammar change: {{forward}} is a new result type value and the
hand-off list uses {{param}} elements.
h2. Out of scope
* No change to {{chain}} or {{ChainingInterceptor}} in this ticket; they keep
working as today.
* Deprecating {{chain}} (planned for 7.7.0, together with a log of which
properties each chain actually copies, as a migration aid) and removing it in
8.0.0 are separate tickets.
h2. Docs
struts-site: a {{forward}} result page (distinguishing it from the
{{dispatcher}} result, which forwards to a resource), the opt-in and hand-off
annotations, and a {{chain}} → {{forward}} migration guide.
--
This message was sent by Atlassian Jira
(v10.3.26#10030026)