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

时间:2017-04-19 02:42:24

标签: java validation dependency-injection guice

我有一个在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) 

1 个答案:

答案 0 :(得分:3)

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

  

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

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

  1. 实现自定义ConstraintValidatorFactory,这在链接文档中有描述,在该工厂中,可以访问guice注入器以获取ServiceA并将其传递给构造函数。 / p>

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

  3. 要获得注射器,您可以执行以下操作(这不是很好的代码,但不知何故,您需要访问注射器)。要存储您的注射器参考,您可以使用Singleton - 在这里我使用枚举实现它:

    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,并且在调用validate方法时,请确保serviceA不为空。

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