2009-10-26 45 views
0

我已使用@NotEmpty標記註釋了字符串字段。Hibernate驗證程序:@NotEmpty不適用於空值

當我試圖堅持與此字段的值「」的實體,它工作正常。機制檢測到驗證錯誤並引發一個InvalidStateException異常來通知問題。

但是,當我試圖堅持與該字段的值爲null的實體時,會引發UndeclaredThrowableException(由InvocationTargetException引起,由PropertyValueException引起:not-null屬性引用null或瞬態值)異常,因爲系統正在嘗試點擊數據庫在不可爲空的字段上具有空值。

問題很明顯:爲什麼驗證機制不能檢測到這種情況?我認爲它應該引發一個InvalidStateException異常,而不是一個UndeclaredThrowableException。

我用的是以下庫:

- hibernate-annotations 3.3.1.GA 
    - hibernate-validator 3.0.0.ga 
    - hibernate-core 3.2.6ga 

,現在我剛剛升級到

- hibernate-annotations 3.4.0.GA 
    - hibernate-validator 3.1.0.GA 
    - hibernate-core 3.3.2 

這些都是最新的穩定版本。

但它仍然無法正常工作。

有什麼想法?

完整的錯誤跟蹤:

java.lang.reflect.UndeclaredThrowableException 
    at $Proxy78.merge(Unknown Source) 
    at com.myApp.persistence.ddg.impl.MergeMethodInterceptor.intercept(MergeMethodInterceptor.java:18) 
    at com.myApp.backoffice.model.cms.dao.IDAOOrganization$$EnhancerByCGLIB$$c21eebfe.merge(<generated>) 
    at com.myApp.cms.components.implementations.DSOrganization.saveOrUpdate(DSOrganization.java:150) 
    at com.myApp.cms.components.implementations.DSOrganization.saveOrUpdate(DSOrganization.java:1) 
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) 
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) 
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) 
    at java.lang.reflect.Method.invoke(Method.java:597) 
    at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:310) 
    at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:182) 
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:149) 
    at com.myApp.persistence.tx.impl.TransactionalInterceptor$1.call(TransactionalInterceptor.java:34) 
    at com.myApp.persistence.tx.impl.TransactionManagerImpl.createSessionAndTransactionAndRunCallable(TransactionManagerImpl.java:261) 
    at com.myApp.persistence.tx.impl.TransactionManagerImpl.runInTransaction(TransactionManagerImpl.java:236) 
    at com.myApp.persistence.tx.impl.TransactionalInterceptor.invoke(TransactionalInterceptor.java:27) 
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:171) 
    at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:204) 
    at $Proxy70.saveOrUpdate(Unknown Source) 
    at com.myApp.cms.components.ValidationTest.test_organization(ValidationTest.java:60) 
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) 
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) 
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) 
    at java.lang.reflect.Method.invoke(Method.java:597) 
    at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:44) 
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15) 
    at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:41) 
    at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:20) 
    at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:28) 
    at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:31) 
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:73) 
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:46) 
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:180) 
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:41) 
    at org.junit.runners.ParentRunner$1.evaluate(ParentRunner.java:173) 
    at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:28) 
    at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:31) 
    at org.junit.runners.ParentRunner.run(ParentRunner.java:220) 
    at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:45) 
    at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38) 
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:460) 
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:673) 
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:386) 
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:196) 
Caused by: java.lang.reflect.InvocationTargetException 
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) 
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) 
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) 
    at java.lang.reflect.Method.invoke(Method.java:597) 
    at com.myApp.persistence.tx.impl.TransactionManagerImpl$TimeoutInvocationHandler.invoke(TransactionManagerImpl.java:176) 
    ... 44 more 
Caused by: org.hibernate.PropertyValueException: not-null property references a null or transient value: com.myApp.backoffice.model.cms.dto.Organization.name 
    at org.hibernate.engine.Nullability.checkNullability(Nullability.java:72) 
    at org.hibernate.event.def.AbstractSaveEventListener.performSaveOrReplicate(AbstractSaveEventListener.java:290) 
    at org.hibernate.event.def.AbstractSaveEventListener.performSave(AbstractSaveEventListener.java:181) 
    at org.hibernate.event.def.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:121) 
    at org.hibernate.event.def.DefaultMergeEventListener.entityIsTransient(DefaultMergeEventListener.java:186) 
    at org.springframework.orm.hibernate3.support.IdTransferringMergeEventListener.entityIsTransient(IdTransferringMergeEventListener.java:58) 
    at org.hibernate.event.def.DefaultMergeEventListener.entityIsDetached(DefaultMergeEventListener.java:240) 
    at org.hibernate.event.def.DefaultMergeEventListener.onMerge(DefaultMergeEventListener.java:120) 
    at org.hibernate.event.def.DefaultMergeEventListener.onMerge(DefaultMergeEventListener.java:53) 
    at org.hibernate.impl.SessionImpl.fireMerge(SessionImpl.java:677) 
    at org.hibernate.impl.SessionImpl.merge(SessionImpl.java:661) 
    at org.hibernate.impl.SessionImpl.merge(SessionImpl.java:665) 
    ... 49 more 

試圖合併事件監聽器註冊了一個SessionFactory的bean:

<property name="eventListeners"> 
    <map> 
    <entry key="merge"> 
     <bean class="org.hibernate.validator.event.ValidateEventListener"/> 
    </entry> 
    </map> 
</property> 

它提出了以下錯誤:

org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'com.myApp.persistence.tx.TransactionalAutoProxyCreator#0' defined in class path resource [com/myApp/backoffice/model/persistence.xml]: Cannot resolve reference to bean 'transactionalInterceptor' while setting bean property 'transactionalInterceptor'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'transactionalInterceptor' defined in class path resource [com/myApp/backoffice/model/persistence.xml]: Cannot resolve reference to bean 'transactionManager' while setting bean property 'transactionManager'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'transactionManager' defined in class path resource [com/myApp/backoffice/model/persistence.xml]: Cannot resolve reference to bean 'sessionFactory' while setting bean property 'sessionFactory'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'sessionFactory' defined in class path resource [com/myApp/backoffice/model/persistence.xml]: Invocation of init method failed; nested exception is java.lang.ArrayStoreException: org.hibernate.validator.event.ValidateEventListener 
     at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveReference(BeanDefinitionValueResolver.java:275) 
     at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveValueIfNecessary(BeanDefinitionValueResolver.java:104) 
     at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyPropertyValues(AbstractAutowireCapableBeanFactory.java:1245) 
     at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1010) 
     at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:472) 
     at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory$1.run(AbstractAutowireCapableBeanFactory.java:409) 
     at java.security.AccessController.doPrivileged(Native Method) 
     at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:380) 
     at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:264) 
     at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:221) 
     at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:261) 
     at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:185) 
     at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:164) 
     at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:881) 
     at org.springframework.context.support.AbstractApplicationContext.registerBeanPostProcessors(AbstractApplicationContext.java:597) 
     at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:366) 
     at org.springframework.context.support.ClassPathXmlApplicationContext.<init>(ClassPathXmlApplicationContext.java:139) 
     at org.springframework.context.support.ClassPathXmlApplicationContext.<init>(ClassPathXmlApplicationContext.java:93) 
     at com.myApp.ContextLoader.getApplicationContext(ContextLoader.java:27) 
     at com.myApp.ContextLoader.getBean(ContextLoader.java:43) 
     at com.myApp.cms.CMSTestContext.getIDSPerson(CMSTestContext.java:200) 
     at com.myApp.cms.CMSTestContext.removePersons(CMSTestContext.java:486) 
     at com.myApp.cms.CMSTestContext.removeEditorialObjs(CMSTestContext.java:376) 
     at com.myApp.cms.CMSTestContext.removeCollections(CMSTestContext.java:323) 
     at com.myApp.cms.CMSTestContext.after(CMSTestContext.java:1572) 
     at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) 
     at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) 
     at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) 
     at java.lang.reflect.Method.invoke(Method.java:597) 
     at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:44) 
     at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15) 
     at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:41) 
     at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:37) 
     at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:73) 
     at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:46) 
     at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:180) 
     at org.junit.runners.ParentRunner.access$000(ParentRunner.java:41) 
     at org.junit.runners.ParentRunner$1.evaluate(ParentRunner.java:173) 
     at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:28) 
     at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:31) 
     at org.junit.runners.ParentRunner.run(ParentRunner.java:220) 
     at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:45) 
     at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38) 
     at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:460) 
     at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:673) 
     at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:386) 
     at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:196) 
    Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'transactionalInterceptor' defined in class path resource [com/myApp/backoffice/model/persistence.xml]: Cannot resolve reference to bean 'transactionManager' while setting bean property 'transactionManager'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'transactionManager' defined in class path resource [com/myApp/backoffice/model/persistence.xml]: Cannot resolve reference to bean 'sessionFactory' while setting bean property 'sessionFactory'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'sessionFactory' defined in class path resource [com/myApp/backoffice/model/persistence.xml]: Invocation of init method failed; nested exception is java.lang.ArrayStoreException: org.hibernate.validator.event.ValidateEventListener 
     at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveReference(BeanDefinitionValueResolver.java:275) 
     at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveValueIfNecessary(BeanDefinitionValueResolver.java:104) 
     at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyPropertyValues(AbstractAutowireCapableBeanFactory.java:1245) 
     at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1010) 
     at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:472) 
     at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory$1.run(AbstractAutowireCapableBeanFactory.java:409) 
     at java.security.AccessController.doPrivileged(Native Method) 
     at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:380) 
     at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:264) 
     at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:221) 
     at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:261) 
     at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:185) 
     at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:164) 
     at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveReference(BeanDefinitionValueResolver.java:269) 
     ... 46 more 
    Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'transactionManager' defined in class path resource [com/myApp/backoffice/model/persistence.xml]: Cannot resolve reference to bean 'sessionFactory' while setting bean property 'sessionFactory'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'sessionFactory' defined in class path resource [com/myApp/backoffice/model/persistence.xml]: Invocation of init method failed; nested exception is java.lang.ArrayStoreException: org.hibernate.validator.event.ValidateEventListener 
     at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveReference(BeanDefinitionValueResolver.java:275) 
     at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveValueIfNecessary(BeanDefinitionValueResolver.java:104) 
     at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyPropertyValues(AbstractAutowireCapableBeanFactory.java:1245) 
     at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1010) 
     at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:472) 
     at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory$1.run(AbstractAutowireCapableBeanFactory.java:409) 
     at java.security.AccessController.doPrivileged(Native Method) 
     at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:380) 
     at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:264) 
     at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:221) 
     at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:261) 
     at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:185) 
     at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:164) 
     at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveReference(BeanDefinitionValueResolver.java:269) 
     ... 59 more 
    Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'sessionFactory' defined in class path resource [com/myApp/backoffice/model/persistence.xml]: Invocation of init method failed; nested exception is java.lang.ArrayStoreException: org.hibernate.validator.event.ValidateEventListener 
     at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1337) 
     at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:473) 
     at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory$1.run(AbstractAutowireCapableBeanFactory.java:409) 
     at java.security.AccessController.doPrivileged(Native Method) 
     at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:380) 
     at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:264) 
     at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:221) 
     at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:261) 
     at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:185) 
     at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:164) 
     at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveReference(BeanDefinitionValueResolver.java:269) 
     ... 72 more 
    Caused by: java.lang.ArrayStoreException: org.hibernate.validator.event.ValidateEventListener 
     at org.hibernate.cfg.Configuration.setListener(Configuration.java:1694) 
     at org.springframework.orm.hibernate3.LocalSessionFactoryBean.buildSessionFactory(LocalSessionFactoryBean.java:721) 
     at org.springframework.orm.hibernate3.AbstractSessionFactoryBean.afterPropertiesSet(AbstractSessionFactoryBean.java:211) 
     at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1368) 
     at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1334) 
     ... 82 more 

在此先感謝。

+0

'@ NotEmpty'不保證財產不爲空;這裏一定有其他的東西。你能發佈整個堆棧跟蹤嗎? – ChssPly76 2009-10-26 20:03:00

+0

我已經添加了錯誤跟蹤到問身體。 當屬性取值「」時,它可以正常工作,但是當它取值爲空時,它不起作用。 注意我在保存前進行合併。 – Alberthoven 2009-10-26 20:19:19

回答

1

首先,「合併之前保存」沒有任何意義。適當時,您可以使用merge()而不是save(),但merge()已經返回一個持久實例 - 以下save()是毫無意義的。其次,默認情況下,merge()不會默認調用pre-insert/pre-update事件監聽器;從而驗證永遠不會執行。合併之前,您可以通過合併事件manually specifying listenermanually invoking validatior解決此問題。

+0

但空值(「」)的價值它的作品!我的意思是,驗證程序檢測到驗證失敗,即使在保存前調用合併。 – Alberthoven 2009-10-26 20:46:11

+0

用空字符串merge()成功保存實體(空字符串不爲空 - 所以沒有Nullability異常)。以下save()調用由於@NotEmpty而失敗的驗證器;整個交易將被回滾。 – ChssPly76 2009-10-26 20:49:29

+0

如何在合併之前強制驗證? ValidateEventListener數組中沒有合併事件 – Alberthoven 2009-10-26 20:54:04

1

我得到了它本身固定,一旦我做了以下同樣的錯誤:

public class CustomEventListener implements PreUpdateEventListener{...} 

而不是早期的代碼是:

public class CustomEventListener{..} 
相關問題