This is an automated email from the ASF dual-hosted git repository.
lukaszlenart pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/struts-site.git
The following commit(s) were added to refs/heads/main by this push:
new 807f7bd88 docs: document ModelDriven parameter binding and
authorization (#319)
807f7bd88 is described below
commit 807f7bd8867831dca5b277cf8c7d487508a81a49
Author: Lukasz Lenart <[email protected]>
AuthorDate: Wed Jul 29 09:42:38 2026 +0200
docs: document ModelDriven parameter binding and authorization (#319)
* docs: document ModelDriven parameter binding and authorization
An action implementing ModelDriven makes its model the target of
@StrutsParameter authorization, so the model's members are bindable
without the annotation. This holds on every input channel — request
parameters, JSON bodies and REST bodies — since they all resolve the
authorization target through the same authorizer.
Document it on the @StrutsParameter page (canonical), with short notes
and cross-links from the Model Driven Interceptor and REST plugin pages,
plus guidance to shape a model as a request DTO rather than a domain or
persistence entity.
Co-Authored-By: Claude Opus 5 <[email protected]>
* Adds ToC
* docs: correct version attribution for ModelDriven exemption
@StrutsParameter was introduced in 6.4.0; the ModelDriven exemption
arrived separately in 7.0.0. The previous wording conflated the two and
read as though the annotation itself were a 7.0.0 feature.
Co-Authored-By: Claude Opus 5 <[email protected]>
* docs: drop 6.x reference from ModelDriven authorization note
@StrutsParameter enforcement is supported from Struts 7.0.0; 6.x is not
a version the annotation's behavior should be characterised against.
Co-Authored-By: Claude Opus 5 <[email protected]>
* docs: add ModelDriven binding note to the Model Driven page
The conceptual Model Driven page is the likelier landing spot for
someone learning the feature, but said only that Struts populates the
model's fields — with no mention that this lifts the @StrutsParameter
requirement, and no DTO guidance. Adds the same short note and
cross-link the other pages carry.
Also corrects the interface's package: it is org.apache.struts2
.ModelDriven in 7.x, not com.opensymphony.xwork2.ModelDriven.
Co-Authored-By: Claude Opus 5 <[email protected]>
---------
Co-authored-by: Claude Opus 5 <[email protected]>
---
source/core-developers/logging-interceptor.md | 4 +++
.../core-developers/message-store-interceptor.md | 4 +++
source/core-developers/model-driven-interceptor.md | 10 +++++++
source/core-developers/model-driven.md | 12 +++++++-
.../core-developers/struts-parameter-annotation.md | 35 ++++++++++++++++++++++
source/plugins/rest/index.md | 7 +++++
6 files changed, 71 insertions(+), 1 deletion(-)
diff --git a/source/core-developers/logging-interceptor.md
b/source/core-developers/logging-interceptor.md
index d551a72a0..9aa5d2937 100644
--- a/source/core-developers/logging-interceptor.md
+++ b/source/core-developers/logging-interceptor.md
@@ -7,6 +7,10 @@ parent:
---
# Logging Interceptor
+{:.no_toc}
+
+* Will be replaced with the ToC, excluding a header
+{:toc}
This interceptor logs the start and end of the execution an action (in
English-only, not internationalized).
diff --git a/source/core-developers/message-store-interceptor.md
b/source/core-developers/message-store-interceptor.md
index 7b4ba6ff8..6ee14adff 100644
--- a/source/core-developers/message-store-interceptor.md
+++ b/source/core-developers/message-store-interceptor.md
@@ -7,6 +7,10 @@ parent:
---
# Message Store Interceptor
+{:.no_toc}
+
+* Will be replaced with the ToC, excluding a header
+{:toc}
An interceptor to store a `ValidationAware` action's messages / errors and
field errors into HTTP Session, such that it
will be retrievable at a later stage. This allows the action's message /
errors and field errors to be available longer
diff --git a/source/core-developers/model-driven-interceptor.md
b/source/core-developers/model-driven-interceptor.md
index be88020a0..a2f309b0b 100644
--- a/source/core-developers/model-driven-interceptor.md
+++ b/source/core-developers/model-driven-interceptor.md
@@ -7,6 +7,10 @@ parent:
---
# Model Driven Interceptor
+{:.no_toc}
+
+* Will be replaced with the ToC, excluding a header
+{:toc}
Watches for `ModelDriven` actions and adds the action's model on to the value
stack.
@@ -26,6 +30,12 @@ In the implementation of `getModel`, acquire an instance of
a business object an
On the page, you can address any JavaBean properties on the business object as
if they were coded directly on the Action
class. The framework pushes the Model object onto the ValueStack.
+Pushing the model onto the stack also makes it the target of parameter binding
and of `@StrutsParameter` authorization:
+the model's members are populated from the request without requiring the
annotation, on every input channel. Shape the
+model as a request DTO holding only the fields the action intends to accept,
not as a domain or persistence entity. See
+[StrutsParameter
Annotation](struts-parameter-annotation.html#modeldriven-actions) for the full
rules.
+{:.alert .alert-warning}
+
Many developers use Spring to acquire the business object. With the addition
of a `setModel` method, the business logic
can be injected automatically.
diff --git a/source/core-developers/model-driven.md
b/source/core-developers/model-driven.md
index 01319e012..28fcf53bc 100644
--- a/source/core-developers/model-driven.md
+++ b/source/core-developers/model-driven.md
@@ -7,16 +7,26 @@ parent:
---
# Model Driven
+{:.no_toc}
+
+* Will be replaced with the ToC, excluding a header
+{:toc}
Struts 2 does not have "forms" like Struts 1 did. In Struts 2 request
parameters are bound directly to fields
in the actions class, and this class is placed on top of the stack when the
action is executed.
-If an action class implements the interface
`com.opensymphony.xwork2.ModelDriven` then it needs to return an object
+If an action class implements the interface `org.apache.struts2.ModelDriven`
then it needs to return an object
from the `getModel()` method. Struts will then populate the fields of this
object with the request parameters,
and this object will be placed on top of the stack once the action is
executed. Validation will also be performed
on this model object, instead of the action. Please read about
[VisitorFieldValidator Annotation](visitor-field-validator-annotation)
which can help you validate model's fields.
+The model is also the target of `@StrutsParameter` authorization: its members
are populated from the request without
+requiring the annotation, on every input channel. Shape the model as a request
DTO holding only the fields the action
+intends to accept, not as a domain or persistence entity. See
+[StrutsParameter
Annotation](struts-parameter-annotation.html#modeldriven-actions) for the full
rules.
+{:.alert .alert-warning}
+
## Interceptor
To use `ModelDriven` actions, make sure that the [Model Driven
Interceptor](model-driven-interceptor) is applied
diff --git a/source/core-developers/struts-parameter-annotation.md
b/source/core-developers/struts-parameter-annotation.md
index 33d5dfdc6..97e3c37ff 100644
--- a/source/core-developers/struts-parameter-annotation.md
+++ b/source/core-developers/struts-parameter-annotation.md
@@ -29,6 +29,41 @@ channel that can populate an action from request data:
- [JSON](../../plugins/json) and [REST](../../plugins/rest) plugins —
per-property
authorization performed during deserialization, so unauthorized fields are
never set.
+## ModelDriven actions
+
+When an action implements `ModelDriven` and the [Model Driven
+Interceptor](model-driven-interceptor.html) has pushed the model onto the value
+stack, the **model** — not the action — is the authorization target, and the
+model's members are exempt from the annotation requirement. The whole model is
+bindable, including its nested properties, whether or not any of its fields or
+accessors carry `@StrutsParameter`.
+
+This follows from what the interface declares: returning an object from
+`getModel()` designates that object as the request surface. The model has
+been the authorization target since Struts 7.0.0.
+
+The exemption holds on **every** input channel listed above — request
+parameters, JSON bodies and REST bodies alike — because they all resolve the
+authorization target the same way. It is not a JSON- or REST-specific behavior.
+
+The exemption is narrowly scoped. It applies only when the action itself
+implements `ModelDriven` *and* the object being populated is its model rather
+than the action. A root object configured elsewhere — for example the JSON
+interceptor's `root` expression on an action that does not implement
+`ModelDriven` — is not exempt, and each member it binds still requires
+`@StrutsParameter`.
+
+The exemption lifts the annotation requirement only. The other parameter-name
+checks — accepted and excluded name patterns, and `ParameterNameAware` — still
+apply to a model's parameters as they do to an action's.
+
+Because the entire model is bindable, a `ModelDriven` model should be a request
+DTO carrying only the fields the action intends to accept from a request, never
+a domain or persistence entity. If you need member-level control over what is
+bindable, use action properties annotated with `@StrutsParameter` rather than
+`ModelDriven`.
+{:.alert .alert-warning}
+
## Usage
The placement of the `@StrutsParameter` annotation is crucial and depends on
how you want to populate your action properties.
diff --git a/source/plugins/rest/index.md b/source/plugins/rest/index.md
index 004d21c34..ba7790930 100644
--- a/source/plugins/rest/index.md
+++ b/source/plugins/rest/index.md
@@ -245,6 +245,13 @@ public class OrdersController implements
ModelDriven<Order> {
In this example, the `ModelDriven` interface is used to ensure that only my
model, the Order object in this case, is
returned to the client, otherwise, the whole `OrdersController` object would
be serialized.
+`ModelDriven` also determines what is bindable *from* the request body: the
model is the target of `@StrutsParameter`
+authorization, so all of `Order` can be populated from an incoming request
without the annotation. Shape such a model as
+a request contract carrying only the fields the controller intends to accept,
rather than as a domain or persistence
+entity — see
[`@StrutsParameter`](../../core-developers/struts-parameter-annotation.html#modeldriven-actions)
for the
+full rules.
+{:.alert .alert-warning}
+
Where's ActionSupport? Normally, you extend ActionSupport when writing Struts
2 actions. In these case, our controller
doesn't do that. Why, you ask? ActionSupport provides a bunch of important
functionality to our actions, including support
for i18n and validation. All of this functionality, in the RESTful case, is
provided by the default interceptor stack