如何解决 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) {
        ...
    }
}