[[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 {bean-validation-site}[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) {
				// ...
        }
	})
----
======