从Springboot 2.6.6升级到2.6.7使用验证(Javax.Validation.constraintDeclarationException:hv000151)的行为更改行为
刚刚最近将Springboot升级为2.6.6至2.6.7,但是尽管Hibernate-Validator的GAV尚未更改(两个版本都使用 org.hibernate.Validator.Validator:Hibernate-validator:6.2.2.3.3.final
jakarta.validation:jakarta.validation-api:2.0.2
),我注意到使用验证API的行为发生了变化。
我能够将其减少到简单的测试用例,以显示2.6.6和2.6.7之间的差异。
注意: 我理解它失败并知道修复程序的原因,但是我不明白的是为什么当Hibernate验证器伪像没有更改时,它只有Springboot 2.6.7才开始失败在版本之间。
要演示,以下是代码和测试用例:
- 首先是POM文件(使用SpringBoot 2.6.6):
<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.6.6</version>
<relativePath/>
</parent>
<groupId>org.example</groupId>
<artifactId>validator</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>demo</name>
<description>Demo project</description>
<properties>
<java.version>1.8</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>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
- 然后是Java接口和类:
package org.example.demo;
public interface WithNameOnCard {
String getNameOnCard();
void setNameOnCard(String nameOnCard);
}
package org.example.demo;
import lombok.Getter;
import lombok.Setter;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
@Getter
@Setter
public class MembershipCard implements WithNameOnCard {
@NotNull
@NotBlank
private String nameOnCard;
@NotNull
private String membershipNumber;
}
package org.example.demo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
- 最后,测试案例:
package org.example.demo;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import javax.validation.ConstraintViolation;
import javax.validation.Validation;
import javax.validation.Validator;
import javax.validation.ValidatorFactory;
import java.util.Set;
public class ValidatorTest {
public static Validator validator;
@BeforeAll
public static void setUp() {
ValidatorFactory factory = Validation.buildDefaultValidatorFactory();
validator = factory.getValidator();
}
@Test
public void whenPropertiesEmptyThenFailValidation() {
MembershipCard membershipCard = new MembershipCard();
Set<ConstraintViolation<MembershipCard>> violations = validator.validate(membershipCard);
Assertions.assertTrue(violations.size() > 0);
}
@Test
public void whenPropertiesNotEmptyThenFailPasses() {
MembershipCard membershipCard = new MembershipCard();
membershipCard.setMembershipNumber("123456");
membershipCard.setNameOnCard("JOHN SMITH");
Set<ConstraintViolation<MembershipCard>> violations = validator.validate(membershipCard);
Assertions.assertEquals(0, violations.size());
}
}
- 运行测试,您可以获得:
[INFO] -------------------------------------------------------
[INFO] T E S T S
[INFO] -------------------------------------------------------
[INFO] Running org.example.demo.ValidatorTest
< ... snipped ... >
[INFO] Tests run: 2, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.196 s - in org.example.demo.ValidatorTest
- 现在更改POM文件,以便使用SpringBoot 2.6.7:
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.6.7</version>
<relativePath/>
</parent>
- 运行测试,您将获得:
INFO] Running org.example.demo.ValidatorTest
<... snipped ...>
[ERROR] Tests run: 2, Failures: 0, Errors: 2, Skipped: 0, Time elapsed: 0.17 s <<< FAILURE! - in org.example.demo.ValidatorTest
[ERROR] whenPropertiesEmptyThenFailValidation Time elapsed: 0.026 s <<< ERROR!
javax.validation.ConstraintDeclarationException: HV000151: A method overriding another method must not redefine the parameter constraint configuration, but method MembershipCard#setNameOnCard(String) redefines the configuration of WithNameOnCard#setNameOnCard(String).
at org.example.demo.ValidatorTest.whenPropertiesEmptyThenFailValidation(ValidatorTest.java:27)
[ERROR] whenPropertiesNotEmptyThenFailPasses Time elapsed: 0.003 s <<< ERROR!
javax.validation.ConstraintDeclarationException: HV000151: A method overriding another method must not redefine the parameter constraint configuration, but method MembershipCard#setNameOnCard(String) redefines the configuration of WithNameOnCard#setNameOnCard(String).
at org.example.demo.ValidatorTest.whenPropertiesNotEmptyThenFailPasses(ValidatorTest.java:37)
[ERROR] Errors:
[ERROR] ValidatorTest.whenPropertiesEmptyThenFailValidation:27 » ConstraintDeclaration
[ERROR] ValidatorTest.whenPropertiesNotEmptyThenFailPasses:37 » ConstraintDeclaration ...
[INFO]
[ERROR] Tests run: 3, Failures: 0, Errors: 2, Skipped: 0
注:如上所述,我了解了错误的原因,以便类和界面必须服从Liskov替代原则。
要么消失的错误的修复程序是:
- 从
withNameOncard
接口中删除setter方法setNameOncard()
。或 - 将验证注释从实现类的字段移动到接口的GETTER方法。或
- 仅将
@notnull
从nameOncard
sigral>成员级
class> class> class>getNameOncard()
方法方法nameOncard
接口,在@notblank
nameOncard
字段中留下@notblank
。 (我实际上不明白的最后一个修复程序。 )
我不明白为什么此错误不是Springboot 2.6.6生成的当Hibernate验证器伪像保持在2.6.6和2.6.7之间。
因此,它一定是导致行为变化的其他事情,但我无法确定它是什么。
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
Spring Boot 2.6.7 升级了Lombok版本。较新的Lombok版本传播字段注释到生成的setter方法。作为解决的工作,您可以通过设置Maven属性来降低Lombok版本:
Spring Boot 2.6.7 upgraded the Lombok version. The newer Lombok version propagates the field annotations to the generated setter methods. As a work around, you can downgrade the Lombok version by setting the Maven property: