Spring Bean Validation @Valid handling

Dormouse picture Dormouse · Jul 17, 2014 · Viewed 23.5k times · Source

I have created a Spring MVC REST service using Bean Validation 1.2 with the following method:

@RequestMapping(value = "/valid")
public String validatedMethod(@Valid ValidObject object) {

}

If object isn't valid, Tomcat informs me that The request sent by the client was syntactically incorrect. and my validatedMethod is never called.

How can I get the message that was defined in the ValidObject bean? Should I use some filter or interceptor?

I know that I can rewrite like below, to get the set of ConstraintViolations from the injected Validator, but the above seems more neat...

@RequestMapping(value = "/valid")
public String validatedMethod(ValidObject object) {
    Set<ConstraintViolation<ValidObject>> constraintViolations = validator
            .validate(object);
    if (constraintViolations.isEmpty()) {
        return "valid";
    } else {
        final StringBuilder message = new StringBuilder();
        constraintViolations.forEach((action) -> {
            message.append(action.getPropertyPath());
            message.append(": ");
            message.append(action.getMessage());
        });
        return message.toString();
    }
}

Answer

dharam picture dharam · Jul 17, 2014

I believe a better way of doing this is using ExceptionHandler.

In your Controller you can write ExceptionHandler to handle different exceptions. Below is the code for the same:

@ExceptionHandler(MethodArgumentNotValidException.class)
@ResponseStatus(HttpStatus.BAD_REQUEST)
@ResponseBody
public ValidationFailureResponse validationError(MethodArgumentNotValidException ex) {
    BindingResult result = ex.getBindingResult();
    final List<FieldError> fieldErrors = result.getFieldErrors();

    return new ValidationFailureResponse((FieldError[])(fieldErrors.toArray(new FieldError[fieldErrors.size()])));
}

When you send a bad request to the Controller, the validator throws an exception of type MethodArgumentNotValidException. So the ideal way would be to write an exception handler to specifically handle this exception.

There you can create a beautiful response to tell the user of things which went wrong. I advocate this, because you have to write this just once and many Controller methods can use it. :)

UPDATE

When you use the @Valid annotation for a method argument in the Controller, the validator is invoked automatically and it tries to validate the object, if the object is invalid, it throws MethodArgumentNotValidException.

If Spring finds an ExceptionHandler method for this exception it will execute the code inside this method.

You just need to make sure that the method above is present in your Controller.

Now there is another case when you have multiple Controllers where you want to validate the method arguments. In this case I suggest you to create a ExceptionResolver class and put this method there. Make your Controllers extend this class and your job is done.