2011-12-07 47 views
1

我剛用Hibernate實現了Bean驗證。由Sessionfactory.getCurrentSession.merge調用ConstraintValidator @Autowired bean null

如果我明確調用驗證程序,它將按預期工作,並且按預期注入連接到數據庫的@Autowired DAO bean。

我以前發現我需要在上面的工作之前添加下面的語句。之前我已經廣泛使用了@Autowired bean,但是下面的語句對於由Spring管理的驗證器以及注入到ConstraintValidator中的bean是必需的。

<bean id="validator" 
class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean" /> 

然而,當驗證是SessionFactory.getCurrentSession.merge時自動調用該bean爲空。

事實上,如果我直接用javax.Validation.validate調用調用驗證程序,它會起作用,這讓我認爲我已經正確設置了Spring配置。

我已經閱讀了一些人員無法獲得DAO bean @Autowired的帖子,但在我的情況下,它在合併期間被調用時除外。

下面的日誌輸出顯示驗證器直接被首先調用,然後作爲合併操作的結果被調用。

07.12.2011 01:58:13 INFO [http-8080-1] (FileTypeAndClassValidator:isValid) - Validating ... 
07.12.2011 01:58:13 INFO [http-8080-1] (ConstraintValidatorHelper:getPropertyValue) - propertyName=className, returnValue=com.twoh.dto.PurchaseOrder 
07.12.2011 01:58:13 INFO [http-8080-1] (ConstraintValidatorHelper:getPropertyValue) - propertyName=fileTypeId, returnValue=4 
07.12.2011 01:58:13 INFO [http-8080-1] (QueryUtil:createHQLQuery) - select ft.id from FileType ft where ft.id = :fileTypeId and ft.fileClassName = :fileClassName 
07.12.2011 01:58:13 INFO [http-8080-1] (BaseDAO:merge) - Entity: com.twoh.dto.PurchaseOrder: 1036. 
07.12.2011 01:58:13 INFO [http-8080-1] (FileTypeAndClassValidator:isValid) - Validating ... 
07.12.2011 01:58:13 INFO [http-8080-1] (ConstraintValidatorHelper:getPropertyValue) - propertyName=className, returnValue=com.twoh.dto.PurchaseOrder 
07.12.2011 01:58:13 INFO [http-8080-1] (ConstraintValidatorHelper:getPropertyValue) - propertyName=fileTypeId, returnValue=4 
07.12.2011 01:58:13 INFO [http-8080-1] (FileTypeAndClassValidator:isValid) - java.lang.NullPointerException 

下面是對ConstraintValidator代碼:谷歌搜索後,我終於跨過這兩個說明它具有解決該問題的網站來了約18小時

package com.twoh.dto.ConstraintValidation; 

import javax.validation.ConstraintValidator; 
import javax.validation.ConstraintValidatorContext; 

import org.apache.commons.logging.Log; 
import org.apache.commons.logging.LogFactory; 
import org.springframework.beans.factory.annotation.Autowired; 
import org.springframework.stereotype.Component; 

import com.twoh.dao.IQueryUtil; 

@Component 
public class FileTypeAndClassValidator implements ConstraintValidator<FileTypeAndClass, Object> { 

    private Log logger = LogFactory.getLog(this.getClass()); 

    private String fileClassProperty; 
    private String fileTypeProperty; 

    @Autowired 
    private IQueryUtil queryUtil; 

    public void initialize(FileTypeAndClass constraintAnnotation) { 
     this.fileClassProperty = constraintAnnotation.fileClassProperty(); 
     this.fileTypeProperty = constraintAnnotation.fileTypeProperty(); 
    } 

    public boolean isValid(Object object, ConstraintValidatorContext constraintValidatorContext) { 
     boolean result = true; 

     logger.info("Validating ..."); 

     if (object == null) { 
      result = false; 
     } else { 
      try { 
       String fileClassName = ConstraintValidatorHelper.getPropertyValue(String.class, fileClassProperty, object); 
       Integer fileTypeId = ConstraintValidatorHelper.getPropertyValue(Integer.class, fileTypeProperty, object); 

       result = queryUtil.createHQLQuery((
         "select ft.id" + 
         " from FileType ft" + 
         " where ft.id = :fileTypeId" + 
         " and ft.fileClassName = :fileClassName" 
       )) 
       .setParameter("fileTypeId", fileTypeId) 
       .setParameter("fileClassName", fileClassName) 
       .iterate().hasNext(); 
      } catch (Exception e) { 
       logger.info(e); 
      } 
     } 
     return result; 
    } 
} 

回答

5

確定。 Recipe: Using Hibernate event-based validation with custom JSR-303 validators and Spring autowired injection

在我目前的項目,我們想建立一個自定義的驗證如果電子郵件地址已在數據庫中保存 使用Hibernate我們聯繫實體的任何實例之前就已經存在該 將檢查。該驗證程序需要注入一個DAO,以檢查數據庫中電子郵件地址的存在性是否存在 。令我們驚訝的是,我們認爲會變得輕而易舉的事情更多的是大風。當我們的bean在 Hibernate的基於事件的驗證(在我們的例子中,插入前 事件)被驗證時,Spring的注入 根本不起作用。

在結束我的spring配置結束這樣看:

... 
<bean id="validator" class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean" /> 
<bean id="beanValidationEventListener" class="org.hibernate.cfg.beanvalidation.BeanValidationEventListener"> 
    <constructor-arg ref="validator"/> 
    <constructor-arg ref="hibernateProperties"/> 
</bean> 

... 

<util:properties id="hibernateProperties" location="classpath:hibernate.properties"/> 

<bean id="sessionFactory" 
    class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean"> 
    <property name="dataSource" ref="myDataSource" /> 
    <property name="packagesToScan" value="com.twoh" /> 
    <property name="hibernateProperties" ref="hibernateProperties"/> 
    <property name="eventListeners"> 
     <map> 
      <entry key="pre-insert" value-ref="beanValidationEventListener" /> 
      <entry key="pre-update" value-ref="beanValidationEventListener" /> 
     </map> 
    </property> 
</bean> 
+1

不與Hibernate 4工作。無法在新版本中設置事件監聽器屬性。我也在嘗試一種基於集成商的方法。 stackoverflow.com/a/11672377/161628。但它報告重複事件監聽程序註冊錯誤。 –

4

您可以使用Spring框架提供了以下方法,因爲2.5.1

SpringBeanAutowiringSupport.processInjectionBasedOnCurrentContext(this); 

這是因爲乾淨多了您不必在應用程序中設置任何偵聽器/屬性。

你的代碼看起來就像這樣:

public class ValidUniqueUserEmailValidator implements ConstraintValidator<ValidUniqueUserEmail, Object>, Serializable { 

    private static final long serialVersionUID = 1L; 

    @Autowired 
    private UserDAO userDAO; 

    @Override 
    public void initialize(ValidUniqueUserEmail constraintAnnotation) { 
     SpringBeanAutowiringSupport.processInjectionBasedOnCurrentContext(this); 
    } 

    @Override 
    public boolean isValid(Object value, ConstraintValidatorContext context) { 
     boolean isValid = true; 
     if (value instanceof String) { 
      String email = value.toString(); 
      if (email == null || email.equals("")) { 
       isValid = false; 
      }else{ 
       User user = new User(); 
       user.setEmail(email); 
       isValid = (userDAO.countByEmail(user) > 0); 
      } 
     } 
     return isValid; 

    } 

} 

希望它可以幫助你們走出