【问题标题】:Hibernate Validation + Custom Constraint + java.lang.NullPointerExceptionHibernate 验证 + 自定义约束 + java.lang.NullPointerException
【发布时间】:2015-12-09 21:23:10
【问题描述】:

我已经为此奋斗了好几天,我已经阅读了这里的所有讨论,但没有解决方案......

我有一个自定义约束..

Unique.java

@Target({FIELD, METHOD})
@Retention(RUNTIME)
@Constraint(validatedBy = UniqueConstraintValidator.class)
public @interface Unique {

    String message() default "{src.main.resources}";

    Class<?>[] groups() default {};

    Class<? extends Payload>[] payload() default {};

    String property() default "id";

    Class<?> entity();

}

这由 UniqueConstraintValidator.java

使用
@Transactional
public class UniqueConstraintValidator implements ConstraintValidator<Unique, Serializable> {
    private static final Logger logger = Logger.getLogger(UniqueConstraintValidator.class);
    Session session;


    @Autowired
    private SessionFactory sessionFactory;

    protected Session getSession(){
    return sessionFactory.getCurrentSession();
}

    private Class<?> entityClass;
    private String uniqueField;

    public void initialize(Unique unique) {
        entityClass = unique.entity();
        uniqueField = unique.property();

    }

    @SuppressWarnings("rawtypes")
    public boolean isValid(Serializable property, ConstraintValidatorContext cvContext) {

        String query = String.format("from %s where %s = :field ", entityClass.getName(), uniqueField);
        List list = getSession().createQuery(query).setParameter("field", property).list();
        return list != null && list.size() == 0;
    }

}

现在,我的模型有这个注释,我需要验证字段的唯一性

@NotNull
@Unique(entity = Luce.class, property="numeroLuce")
@Column(name="numero_luce")
public int getNumeroLuce() {
    return numeroLuce;
}

public void setNumeroLuce(int numeroLuce) {
    this.numeroLuce = numeroLuce;
}

现在,我知道自定义注释在更新现有对象时不起作用,但现在我需要了解它是如何工作的。 假设我们要添加一个新对象。

当我尝试保存一个已经存在的值时,我得到了一个正确的验证错误,但如果我想保存一个有效的对象,我得到了一个java.lang.NullPointerException

已编辑这是完整的堆栈跟踪

    exception

org.springframework.web.util.NestedServletException: Request processing failed; nested exception is javax.validation.ValidationException: HV000028: Unexpected exception during isValid call.
    org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:982)
    org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:872)
    javax.servlet.http.HttpServlet.service(HttpServlet.java:648)
    org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:846)
    javax.servlet.http.HttpServlet.service(HttpServlet.java:729)
    org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
root cause

javax.validation.ValidationException: HV000028: Unexpected exception during isValid call.
    org.hibernate.validator.internal.engine.constraintvalidation.ConstraintTree.validateSingleConstraint(ConstraintTree.java:286)
    org.hibernate.validator.internal.engine.constraintvalidation.ConstraintTree.validateConstraints(ConstraintTree.java:133)
    org.hibernate.validator.internal.engine.constraintvalidation.ConstraintTree.validateConstraints(ConstraintTree.java:91)
    org.hibernate.validator.internal.metadata.core.MetaConstraint.validateConstraint(MetaConstraint.java:83)
    org.hibernate.validator.internal.engine.ValidatorImpl.validateConstraint(ValidatorImpl.java:547)
    org.hibernate.validator.internal.engine.ValidatorImpl.validateConstraintsForDefaultGroup(ValidatorImpl.java:487)
    org.hibernate.validator.internal.engine.ValidatorImpl.validateConstraintsForCurrentGroup(ValidatorImpl.java:451)
    org.hibernate.validator.internal.engine.ValidatorImpl.validateInContext(ValidatorImpl.java:403)
    org.hibernate.validator.internal.engine.ValidatorImpl.validate(ValidatorImpl.java:206)
    org.hibernate.cfg.beanvalidation.BeanValidationEventListener.validate(BeanValidationEventListener.java:137)
    org.hibernate.cfg.beanvalidation.BeanValidationEventListener.onPreInsert(BeanValidationEventListener.java:95)
    org.hibernate.action.internal.EntityIdentityInsertAction.preInsert(EntityIdentityInsertAction.java:214)
    org.hibernate.action.internal.EntityIdentityInsertAction.execute(EntityIdentityInsertAction.java:92)
    org.hibernate.engine.spi.ActionQueue.execute(ActionQueue.java:490)
    org.hibernate.engine.spi.ActionQueue.addResolvedEntityInsertAction(ActionQueue.java:195)
    org.hibernate.engine.spi.ActionQueue.addInsertAction(ActionQueue.java:179)
    org.hibernate.engine.spi.ActionQueue.addAction(ActionQueue.java:214)
    org.hibernate.event.internal.AbstractSaveEventListener.addInsertAction(AbstractSaveEventListener.java:324)
    org.hibernate.event.internal.AbstractSaveEventListener.performSaveOrReplicate(AbstractSaveEventListener.java:288)
    org.hibernate.event.internal.AbstractSaveEventListener.performSave(AbstractSaveEventListener.java:194)
    org.hibernate.event.internal.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:125)
    org.hibernate.event.internal.DefaultPersistEventListener.entityIsTransient(DefaultPersistEventListener.java:206)
    org.hibernate.event.internal.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:149)
    org.hibernate.event.internal.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:75)
    org.hibernate.internal.SessionImpl.firePersist(SessionImpl.java:811)
    org.hibernate.internal.SessionImpl.persist(SessionImpl.java:784)
    org.hibernate.internal.SessionImpl.persist(SessionImpl.java:789)
    it.besmart.dao.AbstractDao.persist(AbstractDao.java:37)
    it.besmart.dao.LuceDaoImpl.saveLuci(LuceDaoImpl.java:33)
    it.besmart.service.LuceServiceImpl.saveLuci(LuceServiceImpl.java:33)
    sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    java.lang.reflect.Method.invoke(Method.java:497)
    org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:302)
    org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:190)
    org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:157)
    org.springframework.transaction.interceptor.TransactionInterceptor$1.proceedWithInvocation(TransactionInterceptor.java:99)
    org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:281)
    org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:96)
    org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
    org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:208)
    com.sun.proxy.$Proxy48.saveLuci(Unknown Source)
    it.besmart.controller.LuceController.saveLight(LuceController.java:87)
    sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    java.lang.reflect.Method.invoke(Method.java:497)
    org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:222)
    org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:137)
    org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:110)
    org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:814)
    org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:737)
    org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:85)
    org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:959)
    org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:893)
    org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:970)
    org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:872)
    javax.servlet.http.HttpServlet.service(HttpServlet.java:648)
    org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:846)
    javax.servlet.http.HttpServlet.service(HttpServlet.java:729)
    org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
root cause

java.lang.NullPointerException
    it.besmart.validator.UniqueConstraintValidator.getSession(UniqueConstraintValidator.java:27)
    it.besmart.validator.UniqueConstraintValidator.isValid(UniqueConstraintValidator.java:44)
    it.besmart.validator.UniqueConstraintValidator.isValid(UniqueConstraintValidator.java:18)
    org.hibernate.validator.internal.engine.constraintvalidation.ConstraintTree.validateSingleConstraint(ConstraintTree.java:283)
    org.hibernate.validator.internal.engine.constraintvalidation.ConstraintTree.validateConstraints(ConstraintTree.java:133)
    org.hibernate.validator.internal.engine.constraintvalidation.ConstraintTree.validateConstraints(ConstraintTree.java:91)
    org.hibernate.validator.internal.metadata.core.MetaConstraint.validateConstraint(MetaConstraint.java:83)
    org.hibernate.validator.internal.engine.ValidatorImpl.validateConstraint(ValidatorImpl.java:547)
    org.hibernate.validator.internal.engine.ValidatorImpl.validateConstraintsForDefaultGroup(ValidatorImpl.java:487)
    org.hibernate.validator.internal.engine.ValidatorImpl.validateConstraintsForCurrentGroup(ValidatorImpl.java:451)
    org.hibernate.validator.internal.engine.ValidatorImpl.validateInContext(ValidatorImpl.java:403)
    org.hibernate.validator.internal.engine.ValidatorImpl.validate(ValidatorImpl.java:206)
    org.hibernate.cfg.beanvalidation.BeanValidationEventListener.validate(BeanValidationEventListener.java:137)
    org.hibernate.cfg.beanvalidation.BeanValidationEventListener.onPreInsert(BeanValidationEventListener.java:95)
    org.hibernate.action.internal.EntityIdentityInsertAction.preInsert(EntityIdentityInsertAction.java:214)
    org.hibernate.action.internal.EntityIdentityInsertAction.execute(EntityIdentityInsertAction.java:92)
    org.hibernate.engine.spi.ActionQueue.execute(ActionQueue.java:490)
    org.hibernate.engine.spi.ActionQueue.addResolvedEntityInsertAction(ActionQueue.java:195)
    org.hibernate.engine.spi.ActionQueue.addInsertAction(ActionQueue.java:179)
    org.hibernate.engine.spi.ActionQueue.addAction(ActionQueue.java:214)
    org.hibernate.event.internal.AbstractSaveEventListener.addInsertAction(AbstractSaveEventListener.java:324)
    org.hibernate.event.internal.AbstractSaveEventListener.performSaveOrReplicate(AbstractSaveEventListener.java:288)
    org.hibernate.event.internal.AbstractSaveEventListener.performSave(AbstractSaveEventListener.java:194)
    org.hibernate.event.internal.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:125)
    org.hibernate.event.internal.DefaultPersistEventListener.entityIsTransient(DefaultPersistEventListener.java:206)
    org.hibernate.event.internal.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:149)
    org.hibernate.event.internal.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:75)
    org.hibernate.internal.SessionImpl.firePersist(SessionImpl.java:811)
    org.hibernate.internal.SessionImpl.persist(SessionImpl.java:784)
    org.hibernate.internal.SessionImpl.persist(SessionImpl.java:789)
    it.besmart.dao.AbstractDao.persist(AbstractDao.java:37)
    it.besmart.dao.LuceDaoImpl.saveLuci(LuceDaoImpl.java:33)
    it.besmart.service.LuceServiceImpl.saveLuci(LuceServiceImpl.java:33)
    sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    java.lang.reflect.Method.invoke(Method.java:497)
    org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:302)
    org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:190)
    org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:157)
    org.springframework.transaction.interceptor.TransactionInterceptor$1.proceedWithInvocation(TransactionInterceptor.java:99)
    org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:281)
    org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:96)
    org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
    org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:208)
    com.sun.proxy.$Proxy48.saveLuci(Unknown Source)
    it.besmart.controller.LuceController.saveLight(LuceController.java:87)
    sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    java.lang.reflect.Method.invoke(Method.java:497)
    org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:222)
    org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:137)
    org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:110)
    org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:814)
    org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:737)
    org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:85)
    org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:959)
    org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:893)
    org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:970)
    org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:872)
    javax.servlet.http.HttpServlet.service(HttpServlet.java:648)
    org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:846)
    javax.servlet.http.HttpServlet.service(HttpServlet.java:729)
    org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)

我真的不明白我做错了什么,我知道我是一个 java 菜鸟,但在我看来一切都是正确的。

我在 UniqueConstraintValidator 中添加了一个日志来检查 sessionFactory 是否为空,但我得到了

Session is org.hibernate.internal.SessionFactoryImpl@53911200

所以,它不为空...

提前致谢

【问题讨论】:

  • 您使用的是 Spring Framework,对吗?请把它添加到标签中。
  • 看起来 sessionFactorynull 并且不是自动连接的。
  • 我不知道它是否为空,因为异常出现在我的记录器之前。但是,如果 sessionFactory 为空,这意味着在尝试验证正确值时它也为空,对吗?但在那种情况下我没有得到例外...... PS我添加了标签,谢谢
  • 添加了正确的日志,sessionFactory 不为空...
  • 请调试您的代码并检查发生空指针异常的位置。

标签: java hibernate spring-mvc bean-validation


【解决方案1】:

在这条评论中你会找到答案。

JSR303 custom validators being called twice

首先,当通过表单创建对象时,您通过 spring 验证对象,然后在持久性之前通过 hibernate 验证对象(这是默认行为)。据我了解,hibernate 在 Spring 上下文之外进行验证,因此 Autowired 不起作用。这就是你得到 NullPointerException 的原因。

【讨论】:

    【解决方案2】:

    通过这一行:

    it.besmart.validator.UniqueConstraintValidator.getSession(UniqueConstraintValidator.java:27)
    

    这是说getSession() 抛出一个 NPE。我猜getSession(),如果是第27行,找不到sessionFactory@Autowired 在这里不工作。

    而且,我实际上怀疑将验证器与业务逻辑混合的决定;当传入的值是好的时验证器应该返回true,如果是坏的则返回false;而已。您不应该将其设为@Transactional 并将其保存到数据库中。不,代码有 SRP 的味道。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-01-29
      • 2015-02-13
      • 1970-01-01
      • 1970-01-01
      • 2015-12-29
      • 1970-01-01
      • 2017-04-14
      • 1970-01-01
      相关资源
      最近更新 更多