This is an automated email from the ASF dual-hosted git repository.

lukaszlenart pushed a commit to branch docs/modeldriven-parameter-binding
in repository https://gitbox.apache.org/repos/asf/struts-site.git

commit 29c03826356ceef24fe53e024cad10f079bba8dc
Author: Lukasz Lenart <[email protected]>
AuthorDate: Wed Jul 29 09:13:14 2026 +0200

    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]>
---
 source/core-developers/model-driven-interceptor.md |  6 ++++
 .../core-developers/struts-parameter-annotation.md | 36 ++++++++++++++++++++++
 source/plugins/rest/index.md                       |  7 +++++
 3 files changed, 49 insertions(+)

diff --git a/source/core-developers/model-driven-interceptor.md 
b/source/core-developers/model-driven-interceptor.md
index be88020a0..f23c50420 100644
--- a/source/core-developers/model-driven-interceptor.md
+++ b/source/core-developers/model-driven-interceptor.md
@@ -26,6 +26,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/struts-parameter-annotation.md 
b/source/core-developers/struts-parameter-annotation.md
index 33d5dfdc6..d9d46943d 100644
--- a/source/core-developers/struts-parameter-annotation.md
+++ b/source/core-developers/struts-parameter-annotation.md
@@ -29,6 +29,42 @@ 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 `@StrutsParameter` enforcement was introduced in
+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 

Reply via email to