Spring-boot: Declaring spring-boot-starter-validation dependency should provide MethodValidationPostProcessor bean

Created on 25 Jun 2016  路  4Comments  路  Source: spring-projects/spring-boot

I wanted to use bean-validation for parameters of a @RestController method.

Turns out that even with the inclusion of the starter-validation dependency:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-validation</artifactId>
</dependency>

one needs to manually define a MethodValidationPostProcessor as shown below.
If spring-boot provided such a bean ootb then user's could just work
with the annotations like @Validated and the JSR-303/349 stuff.

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.validation.annotation.Validated;
import org.springframework.validation.beanvalidation.MethodValidationPostProcessor;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.validation.constraints.Size;
import java.util.Map;

import static java.lang.String.format;
import static java.util.Collections.singletonMap;

@SpringBootApplication
public class MvcWebApp {

    public static void main(String[] args) {
        SpringApplication.run(MvcWebApp.class, args);
    }

    @Bean //this could be provided via auto-configuration
    MethodValidationPostProcessor methodValidationPostProcessor() {
        return new MethodValidationPostProcessor();
    }
}

@RestController
@Validated
@RequestMapping("/api")
class HelloResource {


    @RequestMapping("/greet/{name}")
    public Map<String, String> greet(@PathVariable("name") @Size(min = 3, max = 10, message = "You messed up!") String name) {
        return singletonMap("greeting", format("Hello %s", name));
    }
}
enhancement

Most helpful comment

Would also be nice to have a default @ExceptionHandler(value = {ConstraintViolationException.class}) definition e.g.:

@ExceptionHandler(value = {ConstraintViolationException.class})
@ResponseStatus(value = HttpStatus.BAD_REQUEST)
public String handleValidationFailure(ConstraintViolationException ex) {

    StringBuilder messages = new StringBuilder();

    for (ConstraintViolation<?> violation : ex.getConstraintViolations()) {
        messages.append(violation.getMessage() + "\n");
    }

    return messages.toString();
}

All 4 comments

Would also be nice to have a default @ExceptionHandler(value = {ConstraintViolationException.class}) definition e.g.:

@ExceptionHandler(value = {ConstraintViolationException.class})
@ResponseStatus(value = HttpStatus.BAD_REQUEST)
public String handleValidationFailure(ConstraintViolationException ex) {

    StringBuilder messages = new StringBuilder();

    for (ConstraintViolation<?> violation : ex.getConstraintViolations()) {
        messages.append(violation.getMessage() + "\n");
    }

    return messages.toString();
}

+1

@michael-simons please use the github reaction feature for simple +1. Thank you.

The current condition is too fragile in practice since Hibernate validator requires EL on the classpath and barfs if that's not the case. If a user tries tot use validation and forget that part, that's fine but this change makes it happen automatically and unconditionally so we should be more defensive.

Was this page helpful?
0 / 5 - 0 ratings