Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Spring Bean Validation @Valid handling

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();
    }
}
like image 605
Dormouse Avatar asked Jul 17 '14 19:07

Dormouse


People also ask

What is difference between @valid and @validated?

The @Valid annotation ensures the validation of the whole object. Importantly, it performs the validation of the whole object graph. However, this creates issues for scenarios needing only partial validation. On the other hand, we can use @Validated for group validation, including the above partial validation.

What happens when @valid fails?

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 .

Where is @valid annotation is used to validate a form?

In controller class: The @Valid annotation applies validation rules on the provided object. The BindingResult interface contains the result of validation.

How do you validate a bean in the Spring?

Some frameworks — such as Spring — have simple ways to trigger the validation process by just using annotations. This is mainly so that we don't have to interact with the programmatic validation API. To validate a bean, we first need a Validator object, which is built using a ValidatorFactory.


2 Answers

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.

like image 198
dharam Avatar answered Oct 05 '22 03:10

dharam


Try this

@RequestMapping(value = "/valid")
public String validatedMethod(@Valid ValidObject object, BindingResult result) {
    StringBuilder builder = new StringBuilder();
    List<FieldError> errors = result.getFieldErrors();
    for (FieldError error : errors ) {
       builder.append(error.getField() + " : " + error.getDefaultMessage());
    } 
    return builder.toString();
}
like image 38
usha Avatar answered Oct 05 '22 03:10

usha