使用Spring进行Java Bean方法约束验证不适用于构造函数

时间:2018-01-25 21:26:16

标签: java spring hibernate-validator spring-validator

我目前正在尝试使用Hibernate Validator实现一些方法约束验证。 我已经定义了

  1. 方法的参数约束
  2. 方法的返回值约束
  3. 构造函数的参数约束
  4. 构造函数的返回值约束
  5. 使用 ExecutableValidator 界面进行手动验证,如Hibernate Validator documentation中所述,适用于1.-4。

    与Spring的集成基本上可以使用 @Validated 来注释bean。 当我尝试使用 @Validated 在Spring容器中验证我的约束时,只有1.和2.,i。即验证方法,工作,但不是构造函数(3.和4。)。

    任何想法,出了什么问题?

    我创建了一个最小的工作示例: 第一个测试用例是成功的,即使它应该提出异常 第二个测试用例失败,因为在调用setter时会抛出ConstraintViolationException(实际上,异常也应该在之前抛出一行)。

    我的客户bean,应该被验证(注意:setFirstName()的参数有 @NotNull 注释):

    @Validated
    public class Customer {
    
      private String firstName;
    
      private String lastName;
    
      public Customer(@NotNull String firstName, @NotNull String lastName) {
          this.firstName = firstName;
          this.lastName = lastName;
      }
    
      public String getFirstName() {
          return firstName;
      }
    
      public void setFirstName(@NotNull String firstName) {
          this.firstName = firstName;
      }
    
      public String getLastName() {
          return lastName;
      }
    
      public void setLastName(String lastName) {
          this.lastName = lastName;
      }
    }
    

    所属的配置:

    @Configuration
    @ComponentScan({ "com.example.demo" })
    public class MethodValidationConfig {
    
      @Bean
      public MethodValidationPostProcessor methodValidationPostProcessor() {
          return new MethodValidationPostProcessor();
      }
    
      @Bean("customer")
      @Scope(BeanDefinition.SCOPE_PROTOTYPE)
      public Customer customer(String firstName, String lastName) {
    
          Customer customer = new Customer(firstName, lastName);
          return customer;
      }
    }
    

    然后是两个测试用例。 如前所述,第一个不会抛出异常,即使它应该。 第二个引发异常,但是在调用setter时,而不是之前。

    @RunWith(SpringJUnit4ClassRunner.class)
    @ContextConfiguration(classes = { MethodValidationConfig.class }, loader = 
    AnnotationConfigContextLoader.class)
    public class DemoApplicationTests {
    
      @Autowired
      private ApplicationContext applicationContext;
    
      @Test
      public void callConstructorWithInvalidParameter(){
    
          Customer c = (Customer) applicationContext.getBean("customer", null, null);
      }
    
      @Test
      public void callSetterWithInvalidParameter(){
    
          Customer c = (Customer) applicationContext.getBean("customer", "John", "Doe");
          c.setFirstName(null);
      }
    
    }
    

    最后是我的pom.xml:

    <?xml version="1.0" encoding="UTF-8"?>
        <project xmlns="http://maven.apache.org/POM/4.0.0" 
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"   
        xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 
        http://maven.apache.org/xsd/maven-4.0.0.xsd">
        <modelVersion>4.0.0</modelVersion>
    
        <groupId>com.example</groupId>
        <artifactId>demo</artifactId>
        <version>0.0.1-SNAPSHOT</version>
        <dependencies>
            <dependency>
                <groupId>org.hibernate</groupId>
                <artifactId>hibernate-validator</artifactId>
                <version>6.0.7.Final</version>
            </dependency>
            <dependency>
                <groupId>org.hibernate</groupId>
                <artifactId>hibernate-validator-annotation-processor</artifactId>
                <version>6.0.7.Final</version>
            </dependency>
            <dependency>
                <groupId>javax.el</groupId>
                <artifactId>javax.el-api</artifactId>
                <version>3.0.0</version>
            </dependency>
            <dependency>
                <groupId>org.glassfish.web</groupId>
                <artifactId>javax.el</artifactId>
                <version>2.2.6</version>
            </dependency>
            <dependency>
                <groupId>junit</groupId>
                <artifactId>junit</artifactId>
                <scope>test</scope>
            </dependency>
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-test</artifactId>
                <version>5.0.2.RELEASE</version>
                <scope>test</scope>
            </dependency>
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-context</artifactId>
                <version>5.0.2.RELEASE</version>
            </dependency>
            <dependency>
                <groupId>junit</groupId>
                <artifactId>junit</artifactId>
                <version>4.12</version>
            </dependency>
        </dependencies>
        <packaging>jar</packaging>
        <name>demo</name>
        <description>Demo project for Spring Boot</description>
        <properties>
            <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
            <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
            <java.version>1.8</java.version>
        </properties>
    </project>
    

1 个答案:

答案 0 :(得分:1)

Spring验证使用AOP。默认情况下使用Spring AOP。 Spring AOP是一个代理托管组件(aka bean)的运行时AOP实现。

由于这个原因,构造函数不能通过spring AOP建议,因此验证不起作用。

对于更复杂的AOP,请考虑Aspectj。或者只是尝试将验证移到方法执行。 (Spring AOP中唯一支持的连接点)。