【问题标题】:@Autowired bean null in ConstraintValidator when invoked by Sessionfactory.getCurrentSession.merge由 Sessionfactory.getCurrentSession.merge 调用时,ConstraintValidator 中的 @Autowired bean null
【发布时间】:2011-12-07 10:04:14
【问题描述】:

我刚刚使用 Hibernate 实现了 Bean 验证。

如果我显式调用验证器,它会按预期工作,并且连接到数据库的 @Autowired DAO bean 会按预期注入。

我之前发现我需要在上面添加下面的语句才能起作用。我之前已经广泛使用了@Autowired bean,但是下面的语句对于验证器由 Spring 管理并且 bean 注入到 ConstraintValidator 中是必要的。

<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 的代码:

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

【问题讨论】:

    标签: hibernate spring bean-validation autowired


    【解决方案1】:

    好吧,经过大约 18 小时的谷歌搜索,我终于找到了一个网站,该网站都描述了它有解决方案的问题。 Recipe: Using Hibernate event-based validation with custom JSR-303 validators and Spring autowired injection

    在我当前的项目中,我们想要构建一个自定义验证器 将检查数据库中是否已存在电子邮件地址 在使用 Hibernate 保存我们的联系人实体的任何实例之前。这个 验证器需要注入 DAO 以检查 数据库中存在电子邮件地址。令我们惊讶的是,什么 我们认为微风更像是大风。 Spring的注入 当我们的 bean 在上下文中被验证时,根本不起作用 Hibernate 的基于事件的验证(在我们的例子中,预插入 事件)。

    最后我的 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>
    

    【讨论】:

    • 不适用于 Hibernate 4。新版本中无法设置事件监听器属性。我也在尝试基于集成器的方法。 stackoverflow.com/a/11672377/161628。但它报告了重复事件侦听器注册错误。
    【解决方案2】:

    你可以使用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;
    
        }
    
    }
    

    希望对大家有所帮助

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-08-14
      • 1970-01-01
      • 1970-01-01
      • 2018-04-25
      • 1970-01-01
      • 1970-01-01
      • 2015-09-29
      • 2018-07-19
      相关资源
      最近更新 更多