JSR-303依赖注入和Hibernate

Jam*_*Jam 9 validation spring hibernate dependency-injection bean-validation

Spring 3.0.2,Hibernate 3.5.0,Hibernate-Validator 4.0.2.GA

我试图使用以下方法将Spring依赖项注入ConstraintValidator:

@PersistenceContext
private EntityManager entityManager;
Run Code Online (Sandbox Code Playgroud)

我已经配置了应用程序上下文:

<bean id="validator" class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean"/>
Run Code Online (Sandbox Code Playgroud)

根据Spring文档,应该允许"自定义ConstraintValidators像其他任何Spring bean一样受益于依赖注入"

在调试器中,我可以看到Spring调用getBean来创建ConstraintValidator.稍后当flush触发preInsert时,会创建并调用另一个ConstraintValidator.问题是EntityManager在这个新的ConstraintValidator中是null.我尝试在ConstraintValidator中注入其他依赖项,这些依赖项始终为null.

有谁知道是否有可能将依赖注入ConstraintValidator?

Jer*_*oen 12

在EntityManager中注入Spring上下文感知ValidatorFactory的最佳方法是使用javax.persistence.validation.factory属性.配置如下:

<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
 <property name="dataSource" ref="dataSource" />
 <property name="jpaVendorAdapter">
  <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
   <property name="databasePlatform" value="org.hibernate.dialect.HSQLDialect" />              
  </bean>
 </property>
 <property name="jpaPropertyMap">
  <map>
   <entry key="javax.persistence.validation.factory" value-ref="validator" />               
  </map>
 </property>
</bean>

<bean id="validator" class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean"/>
Run Code Online (Sandbox Code Playgroud)

请享用!


Dav*_*d M 7

虽然JSR-303(Hibernate Validator是参考实现)实例化我们的自定义ConstraintValidator,但它实际上将实际创建委托给ValidatorFactory.因此,您认为使用Spring的LocalValidatorFactoryBean 应该为整个应用程序中的自定义验证器启用依赖项注入是正确的.

这里的细微之处在于,当处理实体生命周期事件(更新前,插入前,预删除)时,Hibernate本身使用独立的ValidatorFactory而不是Spring上下文中配置的ValidatorFactory.这是设计我认为:Hibernate Validator不知道Spring,所以我们必须告诉Hibernate使用Spring的LocalValidatorFactoryBean而不是创建它自己的.

基本上,在Spring应用程序上下文XML中需要这样的东西:

<!-- The LocalValidatorFactoryBean is able to instantiate custom validators and inject autowired dependencies. -->
<bean id="validator"
      class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean"/>

<!--
   This is the key to link Spring's injection to Hibernate event-based validation.
   Notice the first constructor argument, this is our Spring ValidatorFactory instance.
  -->
<bean id="beanValidationEventListener" class="org.hibernate.cfg.beanvalidation.BeanValidationEventListener">
    <constructor-arg ref="validator"/>
    <constructor-arg ref="hibernateProperties"/>
</bean>

<bean id="mySessionFactory" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
    ...

    <!--
      A reference to our custom BeanValidationEventListener instance is pushed for all events.
      This can of course be customized if you only need a specific event to trigger validations.
    -->
    <property name="eventListeners">
        <map>
            <entry key="pre-update" value-ref="beanValidationEventListener"/>
            <entry key="pre-insert" value-ref="beanValidationEventListener"/>
            <entry key="pre-delete" value-ref="beanValidationEventListener"/>
        </map>
    </property>
</bean>
Run Code Online (Sandbox Code Playgroud)

由于我已经挣扎了一段时间才知道该怎么做,我在Github上放了一个演示应用程序.自述文件是不言自明的.


Mic*_*man 4

似乎在 JPA2 中,持久性提供程序的验证机制默认在预持久、预更新等时启动。

它使用自己的机制来构造验证器,Spring 不参与其中。

目前我能看到的唯一解决方案是在 persistence.xml 中禁用开箱即用的 JPA2 验证:

<persistence-unit name="persistenceUnit" transaction-type="RESOURCE_LOCAL">
  <provider>org.hibernate.ejb.HibernatePersistence</provider>
    <properties>
      <property name="hibernate.show_sql" value="true"/>
      <!-- other props -->
    </properties>
  <validation-mode>NONE</validation-mode>
</persistence-unit>
Run Code Online (Sandbox Code Playgroud)

然后照常使用Spring的LocalValidatiorFactoryBean。然后,您必须像在 JPA2 之前的世界中一样手动调用验证器。

更新:

为了使其完整,另一个解决方案是constraint-validator-factory在 META-INF/validation.xml 中指定 a。

如果这可以是 Spring 的,那就太好了SpringConstraintValidatorFactory,但不幸的是,它需要将 anAutowireCapableBeanFactory传递到其构造函数中,但 JPA2 需要一个带有无参数构造函数的类。

这就留下了创建自己的实现的选项,ConstraintValidatorFactory将验证器从 Spring 中拉出来,但我没有看到任何干净的方法来做到这一点。