在约束验证器中使用 Guice 进行依赖注入

问题描述 投票:0回答:2

我有一个在 ConstraintValidator 的实现中注入类的用例。 我正在使用 Google guice 进行依赖项注入,目前无法在验证器内注入。

我的场景的简化形式

模块内部:

@Provides
@Singleton
public ServiceA getServiceA() {
        return new ServiceA();
}

约束验证器:

public class MyValidator implements ConstraintValidator<ValidS,List<String>> {

    private final ServiceA serviceA;

    @Inject
    public MyValidator(ServiceA serviceA) {
         this.serviceA = serviceA;
    }
    @Override
    public void initialize(final ValidS validS) {
    }

    @Override
    public boolean isValid(final List<String> sList, final ConstraintValidatorContext constraintValidatorContext) {
        System.out.println(serviceA.testInjection());
        //validation code
    }


}

编辑: 添加异常消息:

HV000064: Unable to instantiate ConstraintValidator: class com.validation.MyValidator.
javax.validation.ValidationException: HV000064: Unable to instantiate ConstraintValidator: class com.validation.MyValidator.
    at org.hibernate.validator.internal.util.privilegedactions.NewInstance.run(NewInstance.java:51) ~[hibernate-validator-5.0.1.Final.jar:5.0.1.Final]
    at org.hibernate.validator.internal.util.ReflectionHelper.run(ReflectionHelper.java:671) ~[hibernate-validator-5.0.1.Final.jar:5.0.1.Final]
    at org.hibernate.validator.internal.util.ReflectionHelper.newInstance(ReflectionHelper.java:219) ~[hibernate-validator-5.0.1.Final.jar:5.0.1.Final]
    at org.hibernate.validator.internal.engine.constraintvalidation.ConstraintValidatorFactoryImpl.getInstance(ConstraintValidatorFactoryImpl.java:34) ~[hibernate-validator-5.0.1.Final.jar:5.0.1.Final]
    at org.hibernate.validator.internal.engine.constraintvalidation.ConstraintValidatorManager.createAndInitializeValidator(ConstraintValidatorManager.java:141) ~[hibernate-validator-5.0.1.Final.jar:5.0.1.Final]
    at org.hibernate.validator.internal.engine.constraintvalidation.ConstraintValidatorManager.getInitializedValidator(ConstraintValidatorManager.java:101) ~[hibernate-validator-5.0.1.Final.jar:5.0.1.Final]
    at org.hibernate.validator.internal.engine.constraintvalidation.ConstraintTree.validateConstraints(ConstraintTree.java:125) ~[hibernate-validator-5.0.1.Final.jar:5.0.1.Final]
    at org.hibernate.validator.internal.engine.constraintvalidation.ConstraintTree.validateConstraints(ConstraintTree.java:91) ~[hibernate-validator-5.0.1.Final.jar:5.0.1.Final]
    at org.hibernate.validator.internal.metadata.core.MetaConstraint.validateConstraint(MetaConstraint.java:85) ~[hibernate-validator-5.0.1.Final.jar:5.0.1.Final]
    at org.hibernate.validator.internal.engine.ValidatorImpl.validateConstraint(ValidatorImpl.java:478) ~[hibernate-validator-5.0.1.Final.jar:5.0.1.Final]
    at org.hibernate.validator.internal.engine.ValidatorImpl.validateConstraintsForDefaultGroup(ValidatorImpl.java:424) ~[hibernate-validator-5.0.1.Final.jar:5.0.1.Final]
    at org.hibernate.validator.internal.engine.ValidatorImpl.validateConstraintsForCurrentGroup(ValidatorImpl.java:388) ~[hibernate-validator-5.0.1.Final.jar:5.0.1.Final]
    at org.hibernate.validator.internal.engine.ValidatorImpl.validateInContext(ValidatorImpl.java:340) ~[hibernate-validator-5.0.1.Final.jar:5.0.1.Final]
    at org.hibernate.validator.internal.engine.ValidatorImpl.validate(ValidatorImpl.java:158) ~[hibernate-validator-5.0.1.Final.jar:5.0.1.Final]
    at com.MyClass.validate(MyClass.java:48) 
java validation dependency-injection guice
2个回答
5
投票

您的自定义验证器无法由 Hibernate 实例化,因为 Hibernate 期望验证器具有无参数构造函数(hibernate 文档)

Hibernate Validator 提供的默认 ConstraintValidatorFactory 需要一个公共的无参数构造函数来实例化 ConstraintValidator 实例(请参阅约束验证器)。

所以你基本上有两种可能性:

  1. 实现自定义

    ConstraintValidatorFactory
    ,这在链接文档中进行了描述,在该工厂中,可以访问 guice 注入器以获取
    ServiceA
    并将其传递给构造函数。

  2. 删除

    public MyValidator(ServiceA serviceA)
    构造函数,并尝试在
    ServiceA
    方法中初始化对
    public void initialize(final ValidS validS)
    的引用。在这里你还需要得到 Guice 注射器。

要获取注入器,您可以执行以下操作(这不是很好的代码,但不知何故您需要访问注入器)。要存储您的注射器引用,您可以使用单例 - 这里我通过使用枚举来实现它:

public enum GlobalInjector {
  INSTANCE;
  private Injector injector;
  public Injector getInjector() {
    return injector;
  }
  public void setInjector(Injector injector) {
    this.injector = injector;
  }      
}

我不知道你如何初始化 guice,但你可能有一些这样的代码,所以添加代码来存储注入器:

Injector injector = Guice.createInjector(new ConfigurationModule());
GlobalInjector.INSTANCE.setInjector(injector);

那么你的初始化方法将如下所示:

@Override
public void initialize(final ValidS validS) {
  Injector injector = GlobalInjector.INSTANCE.getInjector();
  if(null != injector) {
    serviceA = injector.getInstance(ServiceA.class);
  }
}

不要忘记检查

GlobalInjector.INSTANCE.getInjector();
是否返回不为 null,并且当调用验证方法时,请确保
serviceA
不为 null。

注意:我个人不喜欢将注入器存储为全局变量(由单例伪装)的想法,但目前我没有更好的想法。该代码未经测试,所以我希望它一切按预期工作。


0
投票

问题也可能是在实体被持久化之前,Hibernate 开始验证默认组。此时,Hibernate 不知道如何使用 @Inject 创建自己的 ConstraintValidator。 (默认的验证组包括未指定 groups 参数的所有注释。有关详细信息,请参阅:分组约束)。

可以更改此行为,方法是完全关闭验证并手动完成所有操作,或者创建组本身并将您自己的注释包含到创建的组中,然后仅手动验证这些自定义组。

以这种方式标记的注释将不再自动加载,因此您可以完全使用您的 自己的 ConstraintValidationFactory 实现(请参阅:Bootstrapping - ConstraintValidatorFactoryGuiceConstraintValidatorFactory.java),可以轻松地将 Guice 注入器注入其中。

最后,您可以在需要时通过简单地调用 Validator 验证方法并传递该方法的第二个参数 - 您的组来验证您的组。

ValidatorFactory validatorFactory = Validation.byDefaultProvider().configure()
              .constraintValidatorFactory(guiceConstraintValidatorFactory)
              .buildValidatorFactory();

Validator validator = validatorFactory.getValidator();

Set<ConstraintViolation<YourEntity>> constraintViolations =
      validator.validate(yourEntity, YourValidationGroup.class);
© www.soinside.com 2019 - 2024. All rights reserved.