Autowired Repository在Custom Constraint Validator中为空

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

我创建了一个Custom Constraint Validator,它必须访问存储库。 现在我无法理解为什么Repository为null。 我尝试使用@Component注释来注释validation器。 我的基本包包含所有这些类是在xml的一部分。 那么我还应该做些什么来确保存储库dependency injection工作。 这就是我的Constraintvalidation器的样子。

public class DonorTypeExistsConstraintValidator implements ConstraintValidator { @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; } } 

更新

包扫描配置:

        

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

更新

更令人费解的是,删除所有preinsert侦听器(在这种情况下只有BeanValidationEventListener)修复了自动assembly问题。 这使事情变得更加复杂。

我甚至没有插入BeanValidationEventListener,如下面的答案中所述。 这实际上与这里的建议相反: JSR-303dependency injection和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 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(); } } 

更新

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

此自定义validation程序在默认validation程序上调用validation,并使作用域执行一些自定义validation。 https://github.com/C4G/V2V/blob/87dc266043f6d623c101d947a88fa0b0ad536355/src/model/collectedsample/CollectedSampleBackingFormValidator.java

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

现在,此自定义约束validation程序中的自动装入的存储库为null。 我想在我的CustomIntegrator中自定义代码,这里的代码存在于https://github.com/C4G/V2V/blob/87dc266043f6d623c101d947a88fa0b0ad536355/src/interceptor/CustomIntegrator.java

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

希望实际的代码可以帮助您回答我的问题。 谢谢!

您使用的是哪个ValidatorFactory 。 或者用另一种方式,热门的引导Beanvalidation? 默认的Bean Validation(和Hibernate Validator作为参考实现)不会将dependency injectionConstraintValidator实例。 至少在Bean Validation 1.0中。

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

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

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

在执行validation时,您是否通过了validation工厂以供JPA使用:

          

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

你在DonorTypeExistsConstraintValidator上有@Component注释吗?

这在过去杀了我。

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; } }