Document method validation improvements

Closes gh-30643
This commit is contained in:
rstoyanchev 2023-07-05 17:07:30 +01:00
parent a03a14797f
commit df2617d575
13 changed files with 409 additions and 69 deletions

View File

@ -267,6 +267,7 @@
***** xref:web/webmvc/mvc-controller/ann-methods/jackson.adoc[]
**** xref:web/webmvc/mvc-controller/ann-modelattrib-methods.adoc[]
**** xref:web/webmvc/mvc-controller/ann-initbinder.adoc[]
**** xref:web/webmvc/mvc-controller/ann-validation.adoc[]
**** xref:web/webmvc/mvc-controller/ann-exceptionhandler.adoc[]
**** xref:web/webmvc/mvc-controller/ann-advice.adoc[]
*** xref:web/webmvc-functional.adoc[]
@ -361,6 +362,7 @@
***** xref:web/webflux/controller/ann-methods/jackson.adoc[]
**** xref:web/webflux/controller/ann-modelattrib-methods.adoc[]
**** xref:web/webflux/controller/ann-initbinder.adoc[]
**** xref:web/webflux/controller/ann-validation.adoc[]
**** xref:web/webflux/controller/ann-exceptions.adoc[]
**** xref:web/webflux/controller/ann-advice.adoc[]
*** xref:web/webflux-functional.adoc[]

View File

@ -123,15 +123,12 @@ Validator, is expected to be present in the classpath and is automatically detec
[[validation-beanvalidation-spring-inject]]
=== Injecting a Validator
=== Inject Jakarta Validator
`LocalValidatorFactoryBean` implements both `jakarta.validation.ValidatorFactory` and
`jakarta.validation.Validator`, as well as Spring's `org.springframework.validation.Validator`.
You can inject a reference to either of these interfaces into beans that need to invoke
validation logic.
You can inject a reference to `jakarta.validation.Validator` if you prefer to work with the Bean
Validation API directly, as the following example shows:
`jakarta.validation.Validator`, so you can inject a reference to the latter to
apply validation logic if you prefer to work with the Bean Validation API directly,
as the following example shows:
[tabs]
======
@ -160,8 +157,15 @@ Kotlin::
----
======
You can inject a reference to `org.springframework.validation.Validator` if your bean
requires the Spring Validation API, as the following example shows:
[[validation-beanvalidation-spring-inject-adapter]]
=== Inject Spring Validator
In addition to implementing `jakarta.validation.Validator`, `LocalValidatorFactoryBean`
also adapts to `org.springframework.validation.Validator`, so you can inject a reference
to the latter if your bean requires the Spring Validation API.
For example:
[tabs]
======
@ -190,9 +194,15 @@ Kotlin::
----
======
When used as `org.springframework.validation.Validator`, `LocalValidatorFactoryBean`
invokes the underlying `jakarta.validation.Validator`, and then adapts
``ContraintViolation``s to ``FieldError``s, and registers them with the `Errors` object
passed into the `validate` method.
[[validation-beanvalidation-spring-constraints]]
=== Configuring Custom Constraints
=== Configure Custom Constraints
Each bean validation constraint consists of two parts:
@ -274,9 +284,8 @@ As the preceding example shows, a `ConstraintValidator` implementation can have
[[validation-beanvalidation-spring-method]]
=== Spring-driven Method Validation
You can integrate the method validation feature supported by Bean Validation 1.1 (and, as
a custom extension, also by Hibernate Validator 4.3) into a Spring context through a
`MethodValidationPostProcessor` bean definition:
You can integrate the method validation feature of Bean Validation into a
Spring context through a `MethodValidationPostProcessor` bean definition:
[tabs]
======
@ -305,11 +314,11 @@ XML::
----
======
To be eligible for Spring-driven method validation, all target classes need to be annotated
To be eligible for Spring-driven method validation, target classes need to be annotated
with Spring's `@Validated` annotation, which can optionally also declare the validation
groups to use. See
{api-spring-framework}/validation/beanvalidation/MethodValidationPostProcessor.html[`MethodValidationPostProcessor`]
for setup details with the Hibernate Validator and Bean Validation 1.1 providers.
for setup details with the Hibernate Validator and Bean Validation providers.
[TIP]
====
@ -320,6 +329,61 @@ xref:core/aop/proxying.adoc#aop-understanding-aop-proxies[Understanding AOP Prox
to always use methods and accessors on proxied classes; direct field access will not work.
====
By default, `jakarta.validation.ConstraintViolationException` is raised with the set of
``ConstraintViolation``s returned by `jakarata.validation.Validator`. As an alternative,
you can have `MethodValidationException` raised instead with ``ConstraintViolation``s
adapted to `MessageSourceResolvable` errors. To enable set the following flag:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
----
import org.springframework.validation.beanvalidation.MethodValidationPostProcessor;
@Configuration
public class AppConfig {
@Bean
public MethodValidationPostProcessor validationPostProcessor() {
MethodValidationPostProcessor processor = new MethodValidationPostProcessor();
processor.setAdaptConstraintViolations(true);
return processor;
}
}
----
XML::
+
[source,xml,indent=0,subs="verbatim,quotes",role="secondary"]
----
<bean class="org.springframework.validation.beanvalidation.MethodValidationPostProcessor">
<property name="adaptConstraintViolations" value="true"/>
</bean>
----
======
`MethodValidationException` contains a list of ``ParameterValidationResult``s which
group errors by method parameter, and each exposes a `MethodParameter`, the argument
value, and a list of `MessageSourceResolvable` errors adapted from
``ConstraintViolation``s. For `@Valid` method parameters with cascaded violations on
fields and properties, the `ParameterValidationResult` is `ParameterErrors` which
implements `org.springframework.validation.Errors` and exposes validation errors as
``FieldError``s.
The adapted `MessageSourceResolvable` errors can be turned into error messages to
display to users through the configured
xref:core/beans/context-introduction.adoc#context-functionality-messagesource[`MessageSource`]
based on locale and language specific resource bundles.
NOTE: Spring MVC and WebFlux have built-in support for method validation, and therefore
for web controller methods there is no need for a class level `@Validated` and an AOP proxy.
See the Spring MVC xref:web/webmvc/mvc-controller/ann-validation.adoc[Validation] section,
the WebFlux xref:web/webflux/controller/ann-validation.adoc[Validation] section,
and the xref:web/webmvc/mvc-controller/ann-validation.adoc[Error Responses] section.

View File

@ -67,23 +67,23 @@ from an existing `ProblemDetail`. This could be done centrally, e.g. from an
[[webflux-ann-rest-exceptions-i18n]]
== Internationalization
== Customization and i18n
[.small]#xref:web/webmvc/mvc-ann-rest-exceptions.adoc#mvc-ann-rest-exceptions-i18n[See equivalent in the Servlet stack]#
It is a common requirement to internationalize error response details, and good practice
to customize the problem details for Spring WebFlux exceptions. This section describes the
support for that.
It is a common requirement to customize and internationalize error response details.
It is also good practice to customize the problem details for Spring WebFlux exceptions
to avoid revealing implementation details. This section describes the support for that.
`ErrorResponse` exposes message codes for "type", "title", and "detail", in addition to
An `ErrorResponse` exposes message codes for "type", "title", and "detail", as well as
message code arguments for the "detail" field. `ResponseEntityExceptionHandler` resolves
these through a xref:core/beans/context-introduction.adoc#context-functionality-messagesource[MessageSource]
and updates the `ProblemDetail` accordingly.
and updates the corresponding `ProblemDetail` fields accordingly.
The default strategy for message codes follows the pattern:
`problemDetail.[type|title|detail].[fully qualified exception class name]`
Some `ErrorResponse` may expose more than one message code, typically adding a suffix
An `ErrorResponse` may expose more than one message code, typically adding a suffix
to the default message code. The table below lists message codes, and arguments for
Spring WebFlux exceptions:
@ -92,28 +92,19 @@ Spring WebFlux exceptions:
|===
| Exception | Message Code | Message Code Arguments
| `UnsupportedMediaTypeStatusException`
| `HandlerMethodValidationException`
| (default)
| `+{0}+` the media type that is not supported, `+{1}+` list of supported media types
| `+{0}+` list all validation errors.
Message codes and arguments for each error are also resolved via `MessageSource`.
| `UnsupportedMediaTypeStatusException`
| (default) + ".parseError"
|
| `MethodNotAllowedException`
| (default)
| `+{0}+` the current HTTP method, `+{1}+` the list of supported HTTP methods
| `MissingRequestValueException`
| (default)
| `+{0}+` a label for the value (e.g. "request header", "cookie value", ...), `+{1}+` the value name
| `UnsatisfiedRequestParameterException`
| (default)
| `+{0}+` the list of parameter conditions
| `WebExchangeBindException`
| (default)
| `+{0}+` the list of global errors, `+{1}+` the list of field errors.
Message codes and arguments for each error within the `BindingResult` are also resolved
via `MessageSource`.
| `NotAcceptableStatusException`
| (default)
| `+{0}+` list of supported media types
@ -126,9 +117,22 @@ via `MessageSource`.
| (default)
| `+{0}+` the failure reason provided to the class constructor
| `MethodNotAllowedException`
| `UnsupportedMediaTypeStatusException`
| (default)
| `+{0}+` the current HTTP method, `+{1}+` the list of supported HTTP methods
| `+{0}+` the media type that is not supported, `+{1}+` list of supported media types
| `UnsupportedMediaTypeStatusException`
| (default) + ".parseError"
|
| `UnsatisfiedRequestParameterException`
| (default)
| `+{0}+` the list of parameter conditions
| `WebExchangeBindException`
| (default)
| `+{0}+` the list of global errors, `+{1}+` the list of field errors.
Message codes and arguments for each error are also resolved via `MessageSource`.
|===

View File

@ -160,10 +160,13 @@ Kotlin::
----
======
Note that use of `@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 method validation applies because other parameters have `@Constraint` annotations,
then `HandlerMethodValidationException` would be raised instead. See the section on
controller method xref:web/webmvc/mvc-controller/ann-validation.adoc[Validation].
TIP: Using `@ModelAttribute` is optional. 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_ that is not resolved by any other argument resolver is treated as an `@ModelAttribute`.

View File

@ -176,6 +176,10 @@ Kotlin::
======
--
If method validation applies because other parameters have `@Constraint` annotations,
then `HandlerMethodValidationException` is raised instead. See the section on
xref:web/webflux/controller/ann-validation.adoc[Validation].
To access all multipart data as a `MultiValueMap`, you can use `@RequestBody`,
as the following example shows:
@ -306,5 +310,3 @@ file upload.
Received part events can also be relayed to another service by using the `WebClient`.
See xref:web/webflux-webclient/client-body.adoc#webflux-client-body-multipart[Multipart Data].

View File

@ -89,4 +89,33 @@ Kotlin::
----
======
You can also declare an `Errors` parameter for access to validation errors, but in
that case the request body must not be a `Mono`, and will be resolved first:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
----
@PostMapping("/accounts")
public void handle(@Valid @RequestBody Account account, Errors errors) {
// use one of the onError* operators...
}
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
----
@PostMapping("/accounts")
fun handle(@Valid @RequestBody account: Mono<Account>) {
// ...
}
----
======
If method validation applies because other parameters have `@Constraint` annotations,
then `HandlerMethodValidationException` is raised instead. For more details, see the
section on xref:web/webflux/controller/ann-validation.adoc[Validation].

View File

@ -0,0 +1,111 @@
[[mvc-ann-validation]]
= Validation
[.small]#xref:web/webmvc/mvc-controller/ann-validation.adoc[See equivalent in the Servlet stack]#
Spring WebFlux 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/webflux/controller/ann-methods/modelattrib-method-args.adoc[@ModelAttribute],
xref:web/webflux/controller/ann-methods/requestbody.adoc[@RequestBody], and
xref:web/webflux/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.
You can configure a `Validator` globally through the
xref:web/webflux/config.adoc#webflux-config-validation[WebMvc config], or locally
through an xref:web/webflux/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) {
// ...
}
})
----
======

View File

@ -67,23 +67,23 @@ from an existing `ProblemDetail`. This could be done centrally, e.g. from an
[[mvc-ann-rest-exceptions-i18n]]
== Internationalization
== Customization and i18n
[.small]#xref:web/webflux/ann-rest-exceptions.adoc#webflux-ann-rest-exceptions-i18n[See equivalent in the Reactive stack]#
It is a common requirement to internationalize error response details, and good practice
to customize the problem details for Spring WebFlux exceptions. This section describes the
support for that.
It is a common requirement to customize and internationalize error response details.
It is also good practice to customize the problem details for Spring MVC exceptions
to avoid revealing implementation details. This section describes the support for that.
`ErrorResponse` exposes message codes for "type", "title", and "detail", in addition to
An `ErrorResponse` exposes message codes for "type", "title", and "detail", as well as
message code arguments for the "detail" field. `ResponseEntityExceptionHandler` resolves
these through a xref:core/beans/context-introduction.adoc#context-functionality-messagesource[MessageSource]
and updates the `ProblemDetail` accordingly.
and updates the corresponding `ProblemDetail` fields accordingly.
The default strategy for message codes follows the pattern:
`problemDetail.[type|title|detail].[fully qualified exception class name]`
Some `ErrorResponse` may expose more than one message code, typically adding a suffix
An `ErrorResponse` may expose more than one message code, typically adding a suffix
to the default message code. The table below lists message codes, and arguments for
Spring MVC exceptions:
@ -100,6 +100,11 @@ Spring MVC exceptions:
| (default)
| `+{0}+` property name, `+{1}+` property value
| `HandlerMethodValidationException`
| (default)
| `+{0}+` list all validation errors.
Message codes and arguments for each error are also resolved via `MessageSource`.
| `HttpMediaTypeNotAcceptableException`
| (default)
| `+{0}+` list of supported media types
@ -131,8 +136,7 @@ Spring MVC exceptions:
| `MethodArgumentNotValidException`
| (default)
| `+{0}+` the list of global errors, `+{1}+` the list of field errors.
Message codes and arguments for each error within the `BindingResult` are also resolved
via `MessageSource`.
Message codes and arguments for each error are also resolvedvia `MessageSource`.
| `MissingRequestHeaderException`
| (default)

View File

@ -6,7 +6,7 @@
By default, if xref:core/validation/beanvalidation.adoc#validation-beanvalidation-overview[Bean Validation] is present
on the classpath (for example, Hibernate Validator), the `LocalValidatorFactoryBean` is
registered as a global xref:core/validation/validator.adoc[Validator] for use with `@Valid` and
`Validated` on controller method arguments.
`@Validated` on controller method arguments.
In Java configuration, you can customize the global `Validator` instance, as the
following example shows:

View File

@ -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`.

View File

@ -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].

View File

@ -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].

View File

@ -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) {
// ...
}
})
----
======