While validating a primitive type or their equivalent (Integer, Boolean) using constraints validation annotations (@Min, @NotNull, ...) Spring Boot throws ConstraintViolationException
. But when validating a parameter using the @Valid
annotation then MethodArgumentNotValidException
is thrown.
I have a class annotated with @ControllerAdvice
to handle the exceptions from the Controllers.
The problem is that depending on the spring-boot-starter-parent
version, the results are pretty much different.
While using the version 2.0.5.RELEASE
I just needed to include a handler for the ConstraintViolationException
class.
But there are some others versions that MethodArgumentNotValidException
is thrown too.
It already was mentioned on a GitHub issue, but no useful answer...
I'll use the lukasniemeier-zalando's example here. For more detail click on the link above.
@Validated // needed to actually trigger validation
@RestController
class MyController {
@RequestMapping
Response serve(
@RequestParam @Min(2) Integer parameter, // throws ConstraintViolationException
@RequestBody @Valid BodyModel body // throws MethodArgumentNotValidException
) {
return new Response();
}
}
I would expect that both validations throws the same exception, no matter which of them, just to be consistent.
Apearently there's no reason to this to be like it is, at least it was what I understood from this other GitHub issue.
Then I just want a answer why Spring Boot throws 2 types of exception to represent the same problem (argument validation).
Note: as mentioned before, using the version 2.0.5.RELEASE
of the spring-boot-starter-parent
it doesn't happens.
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.5.RELEASE</version>
But as reported by the last GitHub issue that I linked, the version 2.0.0.M4
has this behavior, and I also experienced it with the 2.2.0.M3
version.
Exception HandlerThe @ExceptionHandler is an annotation used to handle the specific exceptions and sending the custom responses to the client. Define a class that extends the RuntimeException class. You can define the @ExceptionHandler method to handle the exceptions as shown.
The exception thrown by @Validated when a constraint we specify is violated is of type ConstraintViolationsException , and has no response handler. To intercept the exception and customize our response, we need to build an exception handler using the @ControllerAdvice and @ExceptionHandler annotations.
They are handled by different validation mechanisms. The @Validated
on the class is handled by the MethodValidationInterceptor
which is a generic purpose validation mechanism for classes. Due to this it throws a ConstraintViolationException
. The @Validated
is used here simply because the @Valid
annotation isn't allowed on types. Hence the only way to enable/trigger the MethodValidationInterceptor
is by using the @Validation
annotation.
The @Valid
on the method argument in a controller is handled by the ModelAttributeMethodProcessor
internally and leads to a web specific binding exception, the MethodArgumentNotValidException
. The ModelAttributeMethodProcessor
is called (indirectly) from the RequestMappingHandlerAdapter
when preparing the method invocation. Instead of @Valid
you could also use the @Validated
annotation on the method argument. Spring MVC supports both (it actually supported @Validated
before @Valid
even existed!).
The solution/workaround is to create your own exception-handler which handles the ConstraintViolationException
the same as a MethodArgumentNotValidException
. Which is also suggested in the GitHub issue you link to.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With