springbean-validationhibernate-validatorspring-framework-beansjakarta-validation

Why isn't Spring kicking in the JSR-303 bean validation?


Wondering why Spring is not getting the Hibernate Bean Validation kicked in. According to the documentation HERE, it requires a MethodValidationPostProcessor in the context and the target spring bean to be annotated with @Validated annotation. I got both of these requirements done, but it is still not working.

I expected an exception at the call to backgroundCheck method due to the fact that the person's name is null and the age is less than 18. For some reason, however, the Person object is not being validated and the method finishes without exceptions.

Here is my setup:

import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.validation.beanvalidation.LocalValidatorFactoryBean;
import org.springframework.validation.beanvalidation.MethodValidationPostProcessor;

@SpringBootApplication
public class Application implements CommandLineRunner {

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

    @Bean
    public LocalValidatorFactoryBean validator() {
        return new LocalValidatorFactoryBean();
    }

    @Bean
    public MethodValidationPostProcessor methodValidationPostProcessor() {
        MethodValidationPostProcessor methodValidationPostProcessor = new MethodValidationPostProcessor();
        methodValidationPostProcessor.setValidator(validator());
        return methodValidationPostProcessor;
    }

    @Override
    public void run(String... args) {

        PersonService personService = new PersonService();

        try {
            personService.backgroundCheck(new Person(null, 4));
        } catch (Exception e) {
            System.out.println("<<< EXCEPTION >>>");
            return;
        }

        System.out.println("<<< NO VALIDATIONS THROWN >>>");
    }
}
import jakarta.validation.Valid;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;

@Validated
@Service
public class PersonService {

    public void backgroundCheck(@Valid Person person) {
        System.out.printf("Running background check for %s%n", person.name());
    }
}
import jakarta.validation.constraints.Min;
import jakarta.validation.constraints.NotBlank;

public record Person(
        @NotBlank(message = "Name must not be blank")
        String name,

        @Min(value = 18, message = "Age should not be less than 18")
        int age) {
}
<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>3.2.3</version>
    <relativePath/> <!-- lookup parent from repository -->
</parent>

<properties>
    <java.version>21</java.version>
</properties>

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

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
    </dependency>
</dependencies>

Any idea what I am missing?


Solution

  • @SpringBootApplication
    public class Application implements CommandLineRunner {
    
        public static void main(String[] args) {
            SpringApplication.run(DemoApplication.class, args);
        }
        
        @Bean
        public LocalValidatorFactoryBean validator() {
            return new LocalValidatorFactoryBean();
        }
    
        @Bean
        public MethodValidationPostProcessor methodValidationPostProcessor() {
            MethodValidationPostProcessor methodValidationPostProcessor = new MethodValidationPostProcessor();
            methodValidationPostProcessor.setValidator(validator());
            return methodValidationPostProcessor;
        }
        // register spring bean!
        @Bean
        public PersonService personService() {
            return new PersonService();
        }
    
        @Override
        public void run(String... args) {
    
            try {
                personService().backgroundCheck(new Person(null, 4));
            } catch (ConstraintViolationException e) {
                System.out.println("<<< EXCEPTION >>>");
                return;
            }
            System.out.println("<<< NO VALIDATIONS THROWN >>>");
        }
    }
    

    Result.

    2024-03-20T13:09:23.676+09:00  INFO 4384 --- [           main]
    <<< EXCEPTION >>>
    

    I hope it will be of help :) thanks.