如何解决 JSR-303 自定义验证器中的依赖关系
How to resolve dependencies in JSR-303 custom validator
假设有一个像这样的自定义验证注释
@Target({ElementType.TYPE, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = {ThirdPartyConstraintValidator.class})
@Documented
public @interface ThirdPartyConstraint {
String message() default "Invalid";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}
以及需要其他服务的相应验证器
public class ThirdPartyConstraintValidator implements ConstraintValidator<ThirdPartyConstraint, Pojo> {
private ThirdPartyService thirdPartyService;
@Override
public void initialize(ThirdPartyConstraint thirdPartyConstraint) {}
@Override
public boolean isValid(Pojo pojo, ConstraintValidatorContext constraintValidatorContext) {
return thirdPartyService.isValid(pojo);
}
public void setThirdPartyService(ThirdPartyService thirdPartyService) {
this.thirdPartyService = thirdPartyService;
}
}
验证上下文是用这样的 Hibernate 实现初始化的
ValidatorFactory factory = Validation.buildDefaultValidatorFactory();
Validator validator = factory.getValidator();
// and then some bean is validated
validator.validate(new Pojo());
在后台 validate
方法调用 class.newInstance()
以获取验证器实现。因此,在 ThirdPartyConstraintValidator
的情况下,永远不会注入依赖项 ThirdPartyService
。
在没有任何框架的情况下使用 ValidationFactory
时,是否可以通过 setter 或构造函数将 ThirdPartyService
注入 ThirdPartyConstraintValidator
?
更新:
根据@matthias 的回答,我更新了我的 ValidatorFactory
以在其中初始化 ThirdPartyConstraintValidator
public <T extends ConstraintValidator<?, ?>> T getInstance(Class<T> aClass) {
if (ThirdPartyConstraintValidator.class.equals(aClass)) {
ThirdPartyConstraintValidator thirdPartyConstraintValidator = new ThirdPartyConstraintValidator();
thirdPartyConstraintValidator.setThirdPartyService(new ThirdPartyService());
return (T) thirdPartyConstraintValidator;
}
return null;
}
您可以实施自定义 ConstraintValidatorFactory 来设置您的依赖项。
见BeanVal Spec or Hibernate Validator Doc
Validator v = Validation.byDefaultProvider().configure()
.constraintValidatorFactory(new MyConstraintValidatorFactory())
.buildValidatorFactory()
.getValidator();
class MyConstraintValidatorFactory implements ConstraintValidatorFactory {
public <T extends ConstraintValidator<?, ?>> T getInstance(final Class<T> arg0) {
//do your stuff to set dependencies
...
}
public void releaseInstance(final ConstraintValidator<?, ?> arg0) {
...
}
}
假设有一个像这样的自定义验证注释
@Target({ElementType.TYPE, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = {ThirdPartyConstraintValidator.class})
@Documented
public @interface ThirdPartyConstraint {
String message() default "Invalid";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}
以及需要其他服务的相应验证器
public class ThirdPartyConstraintValidator implements ConstraintValidator<ThirdPartyConstraint, Pojo> {
private ThirdPartyService thirdPartyService;
@Override
public void initialize(ThirdPartyConstraint thirdPartyConstraint) {}
@Override
public boolean isValid(Pojo pojo, ConstraintValidatorContext constraintValidatorContext) {
return thirdPartyService.isValid(pojo);
}
public void setThirdPartyService(ThirdPartyService thirdPartyService) {
this.thirdPartyService = thirdPartyService;
}
}
验证上下文是用这样的 Hibernate 实现初始化的
ValidatorFactory factory = Validation.buildDefaultValidatorFactory();
Validator validator = factory.getValidator();
// and then some bean is validated
validator.validate(new Pojo());
在后台 validate
方法调用 class.newInstance()
以获取验证器实现。因此,在 ThirdPartyConstraintValidator
的情况下,永远不会注入依赖项 ThirdPartyService
。
在没有任何框架的情况下使用 ValidationFactory
时,是否可以通过 setter 或构造函数将 ThirdPartyService
注入 ThirdPartyConstraintValidator
?
更新:
根据@matthias 的回答,我更新了我的 ValidatorFactory
以在其中初始化 ThirdPartyConstraintValidator
public <T extends ConstraintValidator<?, ?>> T getInstance(Class<T> aClass) {
if (ThirdPartyConstraintValidator.class.equals(aClass)) {
ThirdPartyConstraintValidator thirdPartyConstraintValidator = new ThirdPartyConstraintValidator();
thirdPartyConstraintValidator.setThirdPartyService(new ThirdPartyService());
return (T) thirdPartyConstraintValidator;
}
return null;
}
您可以实施自定义 ConstraintValidatorFactory 来设置您的依赖项。
见BeanVal Spec or Hibernate Validator Doc
Validator v = Validation.byDefaultProvider().configure()
.constraintValidatorFactory(new MyConstraintValidatorFactory())
.buildValidatorFactory()
.getValidator();
class MyConstraintValidatorFactory implements ConstraintValidatorFactory {
public <T extends ConstraintValidator<?, ?>> T getInstance(final Class<T> arg0) {
//do your stuff to set dependencies
...
}
public void releaseInstance(final ConstraintValidator<?, ?> arg0) {
...
}
}