在类级别进行验证时,ConstraintValidator依赖项注入会导致ValidationException

Tho*_*idt 5 spring hibernate hibernate-validator bean-validation

ConstraintValidator在类中使用依赖注入时,在遇到依赖注入时遇到了意外的行为。

实体类:

@Entity
@ValidDemoEntity
public class DemoEntity {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

}
Run Code Online (Sandbox Code Playgroud)

验证批注:

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = {DemoEntityValidator.class})
public @interface ValidDemoEntity {

    String message() default "{some.demo.validator.message}";
    Class<?>[] groups() default {};
    Class<? extends Payload>[] payload() default {};

}
Run Code Online (Sandbox Code Playgroud)

验证器:

public class DemoEntityValidator implements ConstraintValidator<ValidDemoEntity, DemoEntity> {

    private DemoEntityRepository demoEntityRepository;

    public DemoEntityValidator(DemoEntityRepository demoEntityRepository) {
        this.demoEntityRepository = demoEntityRepository;
    }

    @Override
    public void initialize(ValidDemoEntity constraintAnnotation) {

    }

    @Override
    public boolean isValid(DemoEntity demoEntity, ConstraintValidatorContext constraintValidatorContext) {
        return true;
    }
}
Run Code Online (Sandbox Code Playgroud)

测试类别:

@SpringBootTest
public class ValidatorInstantiationTest {

    private Validator validator;

    @Before
    public void setUp() throws Exception {
        ValidatorFactory validatorFactory = Validation.buildDefaultValidatorFactory();
        validator = validatorFactory.getValidator();
    }

    @Test
    public void shouldInitiateAndCallDemoEntityValidator() {
        DemoEntity demoEntity = new DemoEntity();
        validator.validate(demoEntity);
    }

}
Run Code Online (Sandbox Code Playgroud)

验证实体会导致:

javax.validation.ValidationException: HV000064: Unable to instantiate ConstraintValidator: com.example.demo.DemoEntityValidator.
Run Code Online (Sandbox Code Playgroud)

并进一步深入到堆栈跟踪:

Caused by: java.lang.NoSuchMethodException: com.example.demo.DemoEntityValidator.<init>()
Run Code Online (Sandbox Code Playgroud)

这表明Hibernate试图初始化该类而不是让Spring来照顾它。

奇怪的是,依赖项注入可以很好地应用于字段级别的验证。

该代码可从GitHub获得

Sim*_*lli 5

该异常表示没有默认构造函数,因为 Hibernate Validator 尝试实例化您的验证器。

你必须使用Spring。

1 让您的验证器成为 Spring Bean:

@Component
public class DemoEntityValidator implements ConstraintValidator<ValidDemoEntity, DemoEntity> {
Run Code Online (Sandbox Code Playgroud)

2 注入 Spring 提供的验证器并使用 SpringRunner 执行测试:

@SpringBootTest
@RunWith(SpringRunner.class)
public class ValidatorInstantiationTest {

    @Autowired
    private Validator validator;

    @Test
    public void shouldInitiateAndCallDemoEntityValidator() {
        DemoEntity demoEntity = new DemoEntity();
        validator.validate(demoEntity);
    }

}
Run Code Online (Sandbox Code Playgroud)