This version is still in development and is not considered stable yet. For the latest stable version, please use Spring Framework 6.2.12!

Validation

Spring WebFlux has built-in Validation for @RequestMapping methods, including Java Bean Validation. Validation may be applied at one of two levels:

  1. Java Bean Validation is applied individually to an @ModelAttribute, @RequestBody, and @RequestPart method parameter annotated with @jakarta.validation.Valid or Spring’s @Validated so long as it is a command object rather than a container such as Map or Collection, it does not have Errors or BindingResult immediately after in the method signature, and does not otherwise require method validation (see next). WebExchangeBindException is the exception raised when validating a method parameter individually.

  2. Java Bean Validation is applied to the method when @Constraint annotations such as @Min, @NotBlank and others are declared directly on method parameters, or on the method for the return value, and it supersedes any validation that would be applied otherwise to a method parameter individually because method validation covers both method parameter constraints and nested constraints via @Valid. HandlerMethodValidationException is the exception raised validation is applied to the method.

Applications must handle both WebExchangeBindException and HandlerMethodValidationException as either may be raised depending on the controller method signature. The two exceptions, however are designed to be very similar, and can be handled with almost identical code. The main difference is that the former is for a single object while the latter is for a list of method parameters.

@Valid is not a constraint annotation, but rather for nested constraints within an Object. Therefore, by itself @Valid does not lead to method validation. @NotNull on the other hand is a constraint, and adding it to an @Valid parameter leads to method validation. For nullability specifically, you may also use the required flag of @RequestBody or @ModelAttribute.

Method validation may be used in combination with Errors or BindingResult method parameters. However, the controller method is called only if all validation errors are on method parameters with an Errors immediately after. If there are validation errors on any other method parameter then HandlerMethodValidationException is raised.

You can configure a Validator globally through the WebFlux config, or locally through an @InitBinder method in an @Controller or @ControllerAdvice. You can also use multiple validators.

If a controller has a class level @Validated, then 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 Error Responses section provides further details on how WebExchangeBindException 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 ParameterValidationResults 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:

  • Java

  • Kotlin

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