Java 使用 Spring 的 Bean 方法约束验证不适用于构造函数
Java Bean method constraint validation with Spring does not work for constructors
我目前正在尝试使用 Hibernate Validator 实现一些方法约束验证。
我已经定义
- 方法的参数约束
- Return 方法的值约束
- 构造函数的参数约束
- Return 构造函数的值约束
使用 ExecutableValidator 接口的手动验证,如 Hibernate Validator documentation 中所述,非常适合 1.-4.
与 Spring 的集成基本上与使用 @Validated 注释 bean 一起工作。
当我尝试使用 @Validated 在 Spring 容器中验证我的约束时,只有 1. 和 2.,我。 e.方法验证有效,但不适用于构造函数(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>
Spring 验证使用 AOP。默认使用 Spring AOP。 Spring AOP 是一种运行时 AOP 实现,它代理托管组件(也称为 bean)。
出于同样的原因,无法使用 spring AOP 建议构造函数,因此验证将不起作用。
对于更复杂的 AOP,请考虑 Aspectj。或者只是尝试将验证移至方法执行。 (spring AOP 中唯一支持的连接点)。
我目前正在尝试使用 Hibernate Validator 实现一些方法约束验证。 我已经定义
- 方法的参数约束
- Return 方法的值约束
- 构造函数的参数约束
- Return 构造函数的值约束
使用 ExecutableValidator 接口的手动验证,如 Hibernate Validator documentation 中所述,非常适合 1.-4.
与 Spring 的集成基本上与使用 @Validated 注释 bean 一起工作。 当我尝试使用 @Validated 在 Spring 容器中验证我的约束时,只有 1. 和 2.,我。 e.方法验证有效,但不适用于构造函数(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>
Spring 验证使用 AOP。默认使用 Spring AOP。 Spring AOP 是一种运行时 AOP 实现,它代理托管组件(也称为 bean)。
出于同样的原因,无法使用 spring AOP 建议构造函数,因此验证将不起作用。
对于更复杂的 AOP,请考虑 Aspectj。或者只是尝试将验证移至方法执行。 (spring AOP 中唯一支持的连接点)。