java 自定义约束验证器中的自动装配存储库为空

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/13599821/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-31 13:22:21  来源:igfitidea点击:

Autowired Repository is Null in Custom Constraint Validator

javaspringhibernatevalidationbean-validation

提问by Rohit Banga

I have a Spring based webapp. I am using several repository classes with annotations @Repository, @Transactional in my Controllers. That part works fine.

我有一个基于 Spring 的 webapp。我在我的控制器中使用了几个带有注释 @Repository、@Transactional 的存储库类。那部分工作正常。

I created a Custom Constraint Validator which has to access the repository. Now I am not able to understand why the Repository is null. I tried annotating the validator with @Component annotation. My base package containing all these classes is in the part of the xml. So what else should I do to ensure the repository dependency injection works. This is how my Constraint validator looks like.

我创建了一个必须访问存储库的自定义约束验证器。现在我无法理解为什么存储库为空。我尝试使用 @Component 注释来注释验证器。我的包含所有这些类的基本包位于 xml 的一部分。那么我还应该做些什么来确保存储库依赖注入工作。这就是我的约束验证器的样子。

public class DonorTypeExistsConstraintValidator implements
    ConstraintValidator<DonorTypeExists, DonorType> {

  @Autowired
  private DonorTypeRepository donorTypeRepository;

  @Override
  public void initialize(DonorTypeExists constraint) {

  }

  public boolean isValid(DonorType target, ConstraintValidatorContext context) {

   System.out.println("donorType: " + target);
   if (target == null)
     return true;

   try {
    if (donorTypeRepository.isDonorTypeValid(target.getDonorType()))
     return true;
   } catch (Exception e) {
    e.printStackTrace();
   }
   return false;
  }

  public void setDonorRepository(DonorTypeRepository donorTypeRepository) {
    this.donorTypeRepository = donorTypeRepository;
  }
}

Update

更新

Package scan configuration:

包扫描配置:

<context:annotation-config />

<!-- Configures the @Controller programming model -->
<mvc:annotation-driven />

<context:component-scan base-package="controller" />
<context:component-scan base-package="repository" />
<context:component-scan base-package="model" />
<context:component-scan base-package="viewmodel" />

This class is in the package model.donortype. The repository is in the package repository.

此类位于包model.donortype 中。存储库位于包存储库中。

Update

更新

Something more puzzling, removing all preinsert listeners (in this case only BeanValidationEventListener) fixes the autowiring issue. This has complicated the matter even more.

更令人费解的是,删除所有预插入侦听器(在本例中只有 BeanValidationEventListener)修复了自动装配问题。这让事情变得更加复杂。

I am not even inserting the BeanValidationEventListener as described in the answer below. This is infact contrary to the suggestion here: JSR-303 dependency injection and Hibernate

我什至没有按照下面的答案中的描述插入 BeanValidationEventListener 。这实际上与这里的建议相反: JSR-303 dependency injection and Hibernate

  @Override
  public void integrate(Configuration configuration, SessionFactoryImplementor implementor,
                        SessionFactoryServiceRegistry registry) {
      logger.info("Registering event listeners");
      System.out.println("here");
      // you can add duplication strategory for duplicate registrations

      final EventListenerRegistry eventRegistry = registry.getService(EventListenerRegistry.class);
      // prepend to register before or append to register after
      // this example will register a persist event listener

      eventRegistry.prependListeners(EventType.PERSIST, EntitySaveListener.class);
      eventRegistry.appendListeners(EventType.MERGE, EntitySaveListener.class);
      Iterator<PreInsertEventListener> iter = eventRegistry.getEventListenerGroup(EventType.PRE_INSERT).listeners().iterator();
      while (iter.hasNext()) {
        PreInsertEventListener el = iter.next();
        System.out.println(el.getClass());
        BeanValidationEventListener listener = (BeanValidationEventListener) el;
        System.out.println(listener);
        iter.remove();
      }
  }

Update

更新

I am using JPA. I have a backing form for the JPA entities. In the controller I use InitBinder to instantiate a custom validator binder.setValidator(new EntityBackingFormValidator(binder.getValidator()));. Here is the code for this: https://github.com/C4G/V2V/blob/87dc266043f6d623c101d947a88fa0b0ad536355/src/controller/CollectedSampleController.java

我正在使用 JPA。我有 JPA 实体的支持表格。在控制器中,我使用 InitBinder 来实例化自定义验证器binder.setValidator(new EntityBackingFormValidator(binder.getValidator()));。这是代码:https: //github.com/C4G/V2V/blob/87dc266043f6d623c101d947a88fa0b0ad536355/src/controller/CollectedSampleController.java

This custom validator invokes the validation on the default validator and leaves scope to do some custom validations. https://github.com/C4G/V2V/blob/87dc266043f6d623c101d947a88fa0b0ad536355/src/model/collectedsample/CollectedSampleBackingFormValidator.java

这个自定义验证器调用默认验证器上的验证并留下范围来执行一些自定义验证。 https://github.com/C4G/V2V/blob/87dc266043f6d623c101d947a88fa0b0ad536355/src/model/collectedsample/CollectedSampleBackingFormValidator.java

I am using annotations within the entity to create constraints. Apart from the default constraints, I need to define constraints that check whether a entity at the other side of a many-to-one mapping exists or not. Here is the custom constraint validator. https://github.com/C4G/V2V/blob/87dc266043f6d623c101d947a88fa0b0ad536355/src/model/donor/DonorExistsConstraintValidator.java

我在实体中使用注释来创建约束。除了默认约束之外,我还需要定义约束来检查多对一映射另一侧的实体是否存在。这是自定义约束验证器。 https://github.com/C4G/V2V/blob/87dc266043f6d623c101d947a88fa0b0ad536355/src/model/donor/DonorExistsConstraintValidator.java

Now the autowired repository in this custom constraint validator is null. I am trying to customize code in my CustomIntegrator which is present here https://github.com/C4G/V2V/blob/87dc266043f6d623c101d947a88fa0b0ad536355/src/interceptor/CustomIntegrator.java

现在这个自定义约束验证器中的自动装配存储库为空。我正在尝试在我的 CustomIntegrator 中自定义代码,该代码位于此处 https://github.com/C4G/V2V/blob/87dc266043f6d623c101d947a88fa0b0ad536355/src/interceptor/CustomIntegrator.java

and the xml configuration file present here https://github.com/C4G/V2V/blob/87dc266043f6d623c101d947a88fa0b0ad536355/war/WEB-INF/v2v-servlet.xml

和这里的 xml 配置文件 https://github.com/C4G/V2V/blob/87dc266043f6d623c101d947a88fa0b0ad536355/war/WEB-INF/v2v-servlet.xml

Hopefully the actual code will help you to answer my question. Thanks!

希望实际的代码能帮助你回答我的问题。谢谢!

回答by Hardy

Which ValidatorFactoryare you using. Or to put it another way, hot to you bootstrap Bean Validation? Per default Bean Validation (and Hibernate Validator as reference implentation) does not inject dependencies into ConstraintValidatorinstances. At least in Bean Validation 1.0.

您使用的是哪个ValidatorFactory。或者换句话说,对你来说引导 Bean 验证很热?默认情况下,Bean Validation(和 Hibernate Validator 作为参考实现)不会将依赖项注入ConstraintValidator实例。至少在 Bean Validation 1.0 中。

To enable dependency injection you have to configure a custom ConstraintValidatorFactory. Spring offers SpringConstraintValidatorFactorywhich is the default when using LocalValidatorFactoryBean- see http://static.springsource.org/spring/docs/3.0.0.RC3/reference/html/ch05s07.html

要启用依赖注入,您必须配置自定义ConstraintValidatorFactory。Spring 提供SpringConstraintValidatorFactory这是使用LocalValidatorFactoryBean时的默认设置- 请参阅http://static.springsource.org/spring/docs/3.0.0.RC3/reference/html/ch05s07.html

Also, are you using JPA? I assume so, in which case auto validation on life cycle events automatically. Instead of trying to remove event listeners you can just use the property javax.persistence.validation.modeand set it to NONE. I am wondering whether the right validator is used on life cycle based validation.

另外,您使用的是JPA吗?我假设是这样,在这种情况下,会自动对生命周期事件进行自动验证。您可以使用属性javax.persistence.validation.mode并将其设置为 NONE,而不是尝试删除事件侦听器。我想知道是否在基于生命周期的验证中使用了正确的验证器。

It would all depend on your overall Spring configuration and use.

这完全取决于您的整体 Spring 配置和使用。

回答by Gunnar

Do you pass the validator factory to be used by JPA when performing validation:

在执行验证时,您是否通过了 JPA 要使用的验证器工厂:

<bean 
    id="entityManagerFactory" 
    class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
    <property name="jpaPropertyMap">
        <map>
            <entry 
                key="javax.persistence.validation.factory"
                value-ref="validator"/>
            <!-- ... -->
        </map>
    </property>
    <!-- ... -->
</bean>

That's required since otherwise the default factory (as specified in validation.xml) would be used by JPA.

这是必需的,否则JPA 将使用默认工厂(如validation.xml 中指定的)。

回答by Ishara Samantha

No luck with LocalValidatorFactoryBean. I have done some hack to solve this problem.

LocalValidatorFactoryBean 没有运气。我已经做了一些黑客来解决这个问题。

@Component
public class ServiceUtils
{
    private static ServiceUtils instance;

    @Autowired
    private ListableBeanFactory factory;

    @PostConstruct
    public void init()
    {
        instance = this;
    }

    public static ListableBeanFactory getFactory()
    {
        return instance.factory;
    }
}

回答by noplay

Do you have an @Component annotation on the DonorTypeExistsConstraintValidator?

DonorTypeExistsConstraintValidator 上有@Component 注释吗?

That has killed me in the past.

这在过去杀死了我。