Document method validation improvements
Closes gh-30643
This commit is contained in:
@@ -144,7 +144,7 @@ Java::
|
||||
}
|
||||
|
||||
@PostMapping("update")
|
||||
public String update(@Valid AccountForm form, BindingResult result,
|
||||
public String update(AccountForm form, BindingResult result,
|
||||
@ModelAttribute(binding=false) Account account) { // <1>
|
||||
// ...
|
||||
}
|
||||
@@ -166,7 +166,7 @@ Kotlin::
|
||||
}
|
||||
|
||||
@PostMapping("update")
|
||||
fun update(@Valid form: AccountForm, result: BindingResult,
|
||||
fun update(form: AccountForm, result: BindingResult,
|
||||
@ModelAttribute(binding = false) account: Account): String { // <1>
|
||||
// ...
|
||||
}
|
||||
@@ -210,10 +210,15 @@ Kotlin::
|
||||
<1> Validate the `Pet` instance.
|
||||
======
|
||||
|
||||
Note that using `@ModelAttribute` is optional (for example, to set its attributes).
|
||||
By default, any argument that is not a simple value type (as determined by
|
||||
{api-spring-framework}/beans/BeanUtils.html#isSimpleProperty-java.lang.Class-[BeanUtils#isSimpleProperty])
|
||||
and is not resolved by any other argument resolver is treated as if it were annotated
|
||||
with `@ModelAttribute`.
|
||||
If an `@ModelAttribute` is declared without `BindingResult` parameter after it, then
|
||||
`MethodArgumentNotValueException` is raised. However, if method validation applies because
|
||||
other parameters have `@Constraint` annotations, then `HandlerMethodValidationException`
|
||||
is raised instead. For more details, see the section on
|
||||
xref:web/webmvc/mvc-controller/ann-validation.adoc[Validation].
|
||||
|
||||
TIP: Using `@ModelAttribute` is optional. By default, any parameter that is not a simple
|
||||
value type as determined by
|
||||
{api-spring-framework}/beans/BeanUtils.html#isSimpleProperty-java.lang.Class-[BeanUtils#isSimpleProperty]
|
||||
_AND_ that is not resolved by any other argument resolver is treated as an `@ModelAttribute`.
|
||||
|
||||
|
||||
|
||||
@@ -188,8 +188,7 @@ Java::
|
||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||
----
|
||||
@PostMapping("/")
|
||||
public String handle(@Valid @RequestPart("meta-data") MetaData metadata,
|
||||
BindingResult result) {
|
||||
public String handle(@Valid @RequestPart("meta-data") MetaData metadata, Errors errors) {
|
||||
// ...
|
||||
}
|
||||
----
|
||||
@@ -199,12 +198,14 @@ Kotlin::
|
||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||
----
|
||||
@PostMapping("/")
|
||||
fun handle(@Valid @RequestPart("meta-data") metadata: MetaData,
|
||||
result: BindingResult): String {
|
||||
fun handle(@Valid @RequestPart("meta-data") metadata: MetaData, errors: Errors): String {
|
||||
// ...
|
||||
}
|
||||
----
|
||||
======
|
||||
|
||||
If method validation applies because other parameters have `@Constraint` annotations,
|
||||
then `HandlerMethodValidationException` is raised instead. For more details, see the
|
||||
section on xref:web/webmvc/mvc-controller/ann-validation.adoc[Validation].
|
||||
|
||||
|
||||
|
||||
@@ -48,7 +48,7 @@ Java::
|
||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||
----
|
||||
@PostMapping("/accounts")
|
||||
public void handle(@Valid @RequestBody Account account, BindingResult result) {
|
||||
public void handle(@Valid @RequestBody Account account, Errors errors) {
|
||||
// ...
|
||||
}
|
||||
----
|
||||
@@ -58,10 +58,13 @@ Kotlin::
|
||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||
----
|
||||
@PostMapping("/accounts")
|
||||
fun handle(@Valid @RequestBody account: Account, result: BindingResult) {
|
||||
fun handle(@Valid @RequestBody account: Account, errors: Errors) {
|
||||
// ...
|
||||
}
|
||||
----
|
||||
======
|
||||
|
||||
If method validation applies because other parameters have `@Constraint` annotations,
|
||||
then `HandlerMethodValidationException` is raised instead. For more details, see the
|
||||
section on xref:web/webmvc/mvc-controller/ann-validation.adoc[Validation].
|
||||
|
||||
|
||||
@@ -0,0 +1,112 @@
|
||||
[[mvc-ann-validation]]
|
||||
= Validation
|
||||
|
||||
[.small]#xref:web/webflux/controller/ann-validation.adoc[See equivalent in the Reactive stack]#
|
||||
|
||||
Spring MVC has built-in xref:core/validation/validator.adoc[Validation] support for
|
||||
`@RequestMapping` methods, including the option to use
|
||||
xref:core/validation/beanvalidation.adoc[Java Bean Validation].
|
||||
The validation support works on two levels.
|
||||
|
||||
First, method parameters such as
|
||||
xref:web/webmvc/mvc-controller/ann-methods/modelattrib-method-args.adoc[@ModelAttribute],
|
||||
xref:web/webmvc/mvc-controller/ann-methods/requestbody.adoc[@RequestBody], and
|
||||
xref:web/webmvc/mvc-controller/ann-methods/multipart-forms.adoc[@RequestPart] do perform
|
||||
validation if annotated with Jakarta's `@Valid` or Spring's `@Validated` annotation, and
|
||||
raise `MethodArgumentNotValidException` in case of validation errors. If you want to handle
|
||||
the errors in the controller method instead, you can declare an `Errors` or `BindingResult`
|
||||
method parameter immediately after the validated parameter.
|
||||
|
||||
Second, if https://beanvalidation.org/[Java Bean Validation] is present _AND_ other method
|
||||
parameters, e.g. `@RequestHeader`, `@RequestParam`, `@PathVariable` have `@Constraint`
|
||||
annotations, then method validation is applied to all method arguments, raising
|
||||
`HandlerMethodValidationException` in case of validation errors. You can still declare an
|
||||
`Errors` or `BindingResult` after an `@Valid` method parameter, and handle validation
|
||||
errors within the controller method, as long as there are no validation errors on other
|
||||
method arguments. Method validation is also applied to the return value if the method
|
||||
is annotated with `@Valid` or has other `@Constraint` annotations.
|
||||
|
||||
You can configure a `Validator` globally through the
|
||||
xref:web/webmvc/mvc-config/validation.adoc[WebMvc config], or locally through an
|
||||
xref:web/webmvc/mvc-controller/ann-initbinder.adoc[@InitBinder] method in an
|
||||
`@Controller` or `@ControllerAdvice`. You can also use multiple validators.
|
||||
|
||||
NOTE: If a controller has a class level `@Validated`, then
|
||||
xref:core/validation/beanvalidation.adoc#validation-beanvalidation-spring-method[method validation is applied]
|
||||
through an AOP proxy. In order to take advantage of the Spring MVC built-in support for
|
||||
method validation added in Spring Framework 6.1, you need to remove the class level
|
||||
`@Validated` annotation from the controller.
|
||||
|
||||
The xref:web/webmvc/mvc-ann-rest-exceptions.adoc[Error Responses] section provides further
|
||||
details on how `MethodArgumentNotValidException` and `HandlerMethodValidationException`
|
||||
are handled, and also how their rendering can be customized through a `MessageSource` and
|
||||
locale and language specific resource bundles.
|
||||
|
||||
For further custom handling of method validation errors, you can extend
|
||||
`ResponseEntityExceptionHandler` or use an `@ExceptionHandler` method in a controller
|
||||
or in a `@ControllerAdvice`, and handle `HandlerMethodValidationException` directly.
|
||||
The exception contains a list of``ParameterValidationResult``s that group validation errors
|
||||
by method parameter. You can either iterate over those, or provide a visitor with callback
|
||||
methods by controller method parameter type:
|
||||
|
||||
[tabs]
|
||||
======
|
||||
Java::
|
||||
+
|
||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||
----
|
||||
HandlerMethodValidationException ex = ... ;
|
||||
|
||||
ex.visitResults(new HandlerMethodValidationException.Visitor() {
|
||||
|
||||
@Override
|
||||
public void requestHeader(RequestHeader requestHeader, ParameterValidationResult result) {
|
||||
// ...
|
||||
}
|
||||
|
||||
@Override
|
||||
public void requestParam(@Nullable RequestParam requestParam, ParameterValidationResult result) {
|
||||
// ...
|
||||
}
|
||||
|
||||
@Override
|
||||
public void modelAttribute(@Nullable ModelAttribute modelAttribute, ParameterErrors errors) {
|
||||
|
||||
// ...
|
||||
|
||||
@Override
|
||||
public void other(ParameterValidationResult result) {
|
||||
// ...
|
||||
}
|
||||
});
|
||||
----
|
||||
|
||||
Kotlin::
|
||||
+
|
||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||
----
|
||||
// HandlerMethodValidationException
|
||||
val ex
|
||||
|
||||
ex.visitResults(object : HandlerMethodValidationException.Visitor {
|
||||
|
||||
override fun requestHeader(requestHeader: RequestHeader, result: ParameterValidationResult) {
|
||||
// ...
|
||||
}
|
||||
|
||||
override fun requestParam(requestParam: RequestParam?, result: ParameterValidationResult) {
|
||||
// ...
|
||||
}
|
||||
|
||||
override fun modelAttribute(modelAttribute: ModelAttribute?, errors: ParameterErrors) {
|
||||
// ...
|
||||
}
|
||||
|
||||
// ...
|
||||
|
||||
override fun other(result: ParameterValidationResult) {
|
||||
// ...
|
||||
}
|
||||
})
|
||||
----
|
||||
======
|
||||
Reference in New Issue
Block a user