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 23fb2d5bb0 WW-5844 docs: describe httpMethod enforcement in the plugin
stacks and annotation resolution (#372)
23fb2d5bb0 is described below
commit 23fb2d5bb03cd8e92293b3f8b7bca0b630a5b230
Author: Lukasz Lenart <[email protected]>
AuthorDate: Sun Nov 8 15:51:31 2026 +0100
WW-5844 docs: describe httpMethod enforcement in the plugin stacks and
annotation resolution (#372)
restDefaultStack and beanValidationDefaultStack now contain the httpMethod
interceptor, so the action-configuration page lists them with the core
stacks and both plugin pages carry a "Since 7.5.0" paragraph.
The HTTP Methods section gains the resolution rules for method-level and
class-level annotations across the class and interface hierarchy, and the
REST page explains that the interceptor checks the request method itself,
so update() and destroy() reached from a POST form with _method need
@HttpPost as well.
Co-authored-by: Claude Mythos 5.1 <[email protected]>
---
source/core-developers/action-configuration.md | 21 ++++++++++++++--
source/plugins/bean-validation/index.md | 5 ++++
source/plugins/rest/index.md | 35 ++++++++++++++++++++++++++
3 files changed, 59 insertions(+), 2 deletions(-)
diff --git a/source/core-developers/action-configuration.md
b/source/core-developers/action-configuration.md
index 9ae376b4a4..f2a150dc5e 100644
--- a/source/core-developers/action-configuration.md
+++ b/source/core-developers/action-configuration.md
@@ -368,13 +368,30 @@ The attribute requires the 7.5 DTD. An unknown method
name, e.g. `http-method="f
Actions matched by a wildcard or regex pattern keep the restriction declared
on the pattern.
The restriction is enforced by the `httpMethod` interceptor, which is part of
`basicStack`, `defaultStack`,
-`paramsPrepareParamsStack` and the stacks built on them. If an action declares
`http-method` but its interceptors do
-not include `httpMethod`, a warning is logged at startup and the restriction
is not enforced.
+`paramsPrepareParamsStack` and the stacks built on them, as well as the [REST
Plugin](../plugins/rest)'s
+`restDefaultStack` and the [Bean Validation
Plugin](../plugins/bean-validation)'s `beanValidationDefaultStack`.
+If an action declares `http-method` but its interceptors do not include
`httpMethod`, a warning is logged at startup
+and the restriction is not enforced.
The same interceptor enforces the `@AllowedHttpMethod`, `@HttpGet`,
`@HttpPost`, `@HttpPut`, `@HttpDelete` and
`@HttpGetOrPost` annotations on the action class or method. When both the
attribute and an annotation apply,
the request method must be allowed by both.
+Annotations are resolved as follows:
+
+- A method-level annotation applies to the action method the request invokes,
including the implicit `execute()`
+ when the mapping names no method.
+- An annotation on the invoked method itself takes precedence. Otherwise the
interceptor looks for the same method
+ declared on a superclass or on an implemented interface, including
interfaces those extend, and uses the first
+ annotated declaration it finds. Only public instance methods count, so a
private, static or package-private
+ method of the same name on a parent class carries no restriction.
+- Class-level annotations are consulted only when no method-level annotation
applies. They are looked up on the
+ action class, its superclasses and their interfaces in the same way.
+
+The interceptor compares the HTTP method of the request as the container
reports it. The `_method` parameter the
+REST plugin uses to route a POST form to `update` or `destroy` does not change
it, see
+[HTTP method restrictions in
restDefaultStack](../plugins/rest#http-method-restrictions-in-restdefaultstack).
+
### Rejected requests
When the request method is not allowed, the interceptor returns the
`bad-request` result if it can be resolved:
diff --git a/source/plugins/bean-validation/index.md
b/source/plugins/bean-validation/index.md
index 872687a9b7..669f044398 100644
--- a/source/plugins/bean-validation/index.md
+++ b/source/plugins/bean-validation/index.md
@@ -69,6 +69,11 @@ returns the result code `403`, which needs a matching
(global) result to render
`fetchMetadata.disabled` to `true` on the stack for actions that must accept
such requests.
{:.alert .alert-warning}
+Since Struts 7.5.0 `beanValidationDefaultStack` also contains the `httpMethod`
interceptor, placed after
+`servletConfig` as in core's `defaultStack`
([WW-5844](https://issues.apache.org/jira/browse/WW-5844)). The
+`http-method` attribute and the `@HttpGet`, `@HttpPost` and related
annotations are enforced for every package
+extending `struts-bean-validation`, see [HTTP
Methods](/core-developers/action-configuration#http-methods).
+
Here is another example that shows how you can combine bean-validation with
other plugins by configuring your own
Interceptor-Stack (note: this is just a very short example. In a real app you
should take more care about your stack).
You can combine bean validation with classic struts validation (or disable
either) by putting the according interceptors
diff --git a/source/plugins/rest/index.md b/source/plugins/rest/index.md
index 4da7eb1a0d..741cb93c16 100644
--- a/source/plugins/rest/index.md
+++ b/source/plugins/rest/index.md
@@ -82,6 +82,8 @@ The following URL's will invoke its methods:
- `DELETE: /movies/Thrillers` => method=**destroy**, id=**Thrillers**
To simulate the HTTP methods PUT and DELETE, since they aren't supported by
HTML, the HTTP parameter `_method` will be used.
+It changes only which method the mapper selects; the request is still a POST
for the `httpMethod` interceptor, see
+[HTTP method restrictions in
restDefaultStack](#http-method-restrictions-in-restdefaultstack).
Or, expressed as a table:
@@ -394,6 +396,39 @@ check for the stack serving it:
Requests sent by non-browser clients carry no `Sec-Fetch-Site` header and are
not affected.
+### HTTP method restrictions in restDefaultStack
+
+Since Struts 7.5.0 `restDefaultStack` contains the `httpMethod` interceptor,
placed after `servletConfig` as in core's
+`defaultStack` ([WW-5844](https://issues.apache.org/jira/browse/WW-5844)). The
`http-method` attribute and the
+`@AllowedHttpMethod`, `@HttpGet`, `@HttpPost`, `@HttpPut`, `@HttpDelete` and
`@HttpGetOrPost` annotations are enforced
+for every package extending `rest-default`, see [HTTP
Methods](/core-developers/action-configuration#http-methods).
+
+The interceptor checks the HTTP method of the request itself, not the
`_method` parameter. A POST form carrying
+`_method=put` or `_method=delete` is routed to `update` or `destroy`, but the
request stays a POST, so those methods
+must allow POST. `@HttpPut` and `@HttpDelete` alone accept only real PUT and
DELETE requests, as sent by `fetch()`/XHR
+or non-browser clients; combine them with `@HttpPost` when the same method
also serves HTML forms:
+{:.alert .alert-warning}
+
+```java
+public class OrdersController implements ModelDriven<Order> {
+
+ @HttpPost
+ @HttpPut
+ public HttpHeaders update() {
+ ...
+ }
+
+ @HttpPost
+ @HttpDelete
+ public HttpHeaders destroy() {
+ ...
+ }
+}
+```
+
+An XML `http-method` restriction on such an action must likewise include
`post`. A request whose method is not
+allowed receives `405 Method Not Allowed` with an `Allow` header, or the
`bad-request` result when one is mapped.
+
## Resources
+ [http://www.b-simple.de/documents](http://www.b-simple.de/documents) - Short
RESTful Rails tutorial (PDF, multiple languages)