-->
These old forums are deprecated now and set to read-only. We are waiting for you on our new forums!
More modern, Discourse-based and with GitHub/Google/Twitter authentication built-in.

All times are UTC - 5 hours [ DST ]



Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 3 posts ] 
Author Message
 Post subject: Lifecycle Callback Methods - Potential Hibernate Bug
PostPosted: Wed Feb 15, 2006 12:10 pm 
Newbie

Joined: Wed Feb 15, 2006 11:11 am
Posts: 2
Location: London
Hi All,

Hibernate EntityManager: 3.1beta6

This posting relates to a potential bug in the Hibernate EntityManager implementation.

In section 3.4 "Entity Listeners and Callback Methods" of the ejb 3.0 proposed final draft spec document (JSR220), it is written:

"Lifecycle callback methods may throw unchecked/runtime exceptions. A
runtime exception thrown by a callback method that executes within a
transaction causes that transaction to be rolled back."

Which is understandable. In section 3.4.3 an example is offered of an
entity class having a @PrePersist annotated method, validateCreate() which throws an unchecked exception, as follows:

Code:
@PrePersist
protected void validateCreate() {
  if (getBalance() < MIN_REQUIRED_BALANCE)
    throw new AccountException("Insufficient balance to open an account");
}


This example suggests that performing validation in a @PrePersist annotated method in an entity is a reasonable thing to do. It does stand to reason that an entity should have control over validating it's state - it's clearly better encapsulation than having a facading session bean perform validation (for example).

To attempt to use this, I added the following @PrePersist annotated method to an entity named MessageFolder. Note ValidateException extends RuntimeException, and name is a String property in the entity.

Code:
  @PrePersist
  protected void validateFolder() throws ValidateException
  {
    if(getName() == null || "".equals(getName()))
    {
      throw new ValidateException("error.no.folder.name");
    }
  }


Using a suitable instance of an EntityManager with an extended application managed persistence context and attempting to persist() a new MessageFolder entity which has no name property set results in the stack track seen below.

Note the specific ValidateException thrown is not seen - therefore rendering the throwing of such an exception, and it's intended purpose (to report back to the object trying to persist the entity that there's a problem with the unmanaged new entity's state) is near unusable.

A better implementation would be for the transaction to roll back, and for the container to return the exception thrown, without wrapping it.

javax.ejb.EJBException: Transaction was rolled back:
org.hibernate.PersistentObjectException: detached entity passed to persist:
com.formicary.epix.module.message.MessageFolder; nested exception is:
org.hibernate.PersistentObjectException:
detached entity passed to persist:
com.formicary.epix.module.message.MessageFolder
org.hibernate.PersistentObjectException: detached entity passed to
persist: com.formicary.epix.module.message.MessageFolder
at
org.hibernate.event.def.DefaultPersistEventListener.onPersist(Default
PersistEventListener.java:79)
at
org.hibernate.event.def.DefaultPersistEventListener.onPersist(Default
PersistEventListener.java:38)
at org.hibernate.impl.SessionImpl.firePersist(SessionImpl.java:640)
at org.hibernate.impl.SessionImpl.persist(SessionImpl.java:614)
at org.hibernate.impl.SessionImpl.persist(SessionImpl.java:618)
at
org.hibernate.ejb.AbstractEntityManagerImpl.persist(AbstractEntityMan
agerImpl.java:127)
at
com.formicary.epix.module.message.MessageModuleBean.createFolder(MessageModuleBean.java:129)
at
MessageModule_StatelessSessionBeanWrapper0.createFolder(MessageModule_StatelessSessionBeanWrapper0.java:1052)
at
com.formicary.epix.actions.message.MessageAction.doAddFolder(MessageAction.java:384)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at
sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at
sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAcces
sorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:585)
at
webwork.util.InjectionUtils$DefaultInjectionImpl.invoke(InjectionUtils.java:61)
at webwork.util.InjectionUtils.invoke(InjectionUtils.java:52)
at webwork.action.ActionSupport.invokeCommand(ActionSupport.java:417)
at webwork.action.ActionSupport.execute(ActionSupport.java:146)
at
webwork.dispatcher.GenericDispatcher.executeAction(GenericDispatcher.java:132)
at
webwork.dispatcher.ServletDispatcher.service(ServletDispatcher.java:175)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:333)
at com.evermind._ha.doFilter(.:59)
at
com.formicary.epix.filter.SmartURLFilter.doFilter(SmartURLFilter.java:123)
at com.evermind._gz.doFilter(.:16)
at
com.formicary.epix.filter.SmartURLFilter.doFilter(SmartURLFilter.java:63)
at com.evermind._gz.doFilter(.:20)
at
com.formicary.epix.filter.CommunityFilter.doFilter(CommunityFilter.java:336)
at com.evermind._gz.doFilter(.:20)
at
com.formicary.epix.filter.CommunityFilter.doFilter(CommunityFilter.java:336)
at com.evermind._gz.doFilter(.:20)
at
com.opensymphony.module.sitemesh.filter.PageFilter.parsePage(PageFilter.java:119)
at
com.formicary.epix.filter.SitemeshFilter.parsePage(SitemeshFilter.java:27)
at
com.opensymphony.module.sitemesh.filter.PageFilter.doFilter(PageFilte
r.java:55)
at
com.formicary.epix.filter.ProxyPageFilter.doFilter(ProxyPageFilter.java:37)
at com.evermind._gz.doFilter(.:20)
at
com.formicary.epix.filter.CommunityPrefixFilter.doFilter(CommunityPrefixFilter.java:70)
at com.evermind._gz.doFilter(.:20)
at
com.formicary.epix.filter.LoginFilter.doFilter(LoginFilter.java:86)
at com.evermind._gz.doFilter(.:20)
at
com.formicary.epix.filter.LoginFilter.doFilter(LoginFilter.java:653)
at com.evermind._gz.doFilter(.:20)
at
com.formicary.epix.filter.RequestFilter.doFilter(RequestFilter.java:261)
at com.evermind._csb._pud(.:379)
at com.evermind._csb._bqc(.:176)
at com.evermind._ax._ltc(.:668)
at com.evermind._ax._ucb(.:193)
at com.evermind._bf.run(.:62)
javax.ejb.EJBException: Transaction was rolled back:
org.hibernate.PersistentObjectException: detached entity passed to persist:
com.formicary.epix.module.message.MessageFolder; nested exception is: org.hibernate.PersistentObjectException:
detached entity passed to persist:
com.formicary.epix.module.message.MessageFolder
at
MessageModule_StatelessSessionBeanWrapper0.createFolder(MessageModule_StatelessSessionBeanWrapper0.java:1087)
at
com.formicary.epix.actions.message.MessageAction.doAddFolder(MessageAction.java:384)
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:585)
at
webwork.util.InjectionUtils$DefaultInjectionImpl.invoke(InjectionUtils.java:61)
at webwork.util.InjectionUtils.invoke(InjectionUtils.java:52)
at webwork.action.ActionSupport.invokeCommand(ActionSupport.java:417)
at webwork.action.ActionSupport.execute(ActionSupport.java:146)
at
webwork.dispatcher.GenericDispatcher.executeAction(GenericDispatcher.java:132)
at
webwork.dispatcher.ServletDispatcher.service(ServletDispatcher.java:175)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:333)
at com.evermind._ha.doFilter(.:59)
at
com.formicary.epix.filter.SmartURLFilter.doFilter(SmartURLFilter.java:123)
at com.evermind._gz.doFilter(.:16)
at
com.formicary.epix.filter.SmartURLFilter.doFilter(SmartURLFilter.java:63)
at com.evermind._gz.doFilter(.:20)
at
com.formicary.epix.filter.CommunityFilter.doFilter(CommunityFilter.java:336)
at com.evermind._gz.doFilter(.:20)
at
com.formicary.epix.filter.CommunityFilter.doFilter(CommunityFilter.java:336)
at com.evermind._gz.doFilter(.:20)
at
com.opensymphony.module.sitemesh.filter.PageFilter.parsePage(PageFilter.java:119)
at
com.formicary.epix.filter.SitemeshFilter.parsePage(SitemeshFilter.java:27)
at
com.opensymphony.module.sitemesh.filter.PageFilter.doFilter(PageFilter.java:55)
at
com.formicary.epix.filter.ProxyPageFilter.doFilter(ProxyPageFilter.java:37)
at com.evermind._gz.doFilter(.:20)
at
com.formicary.epix.filter.CommunityPrefixFilter.doFilter(CommunityPrefixFilter.java:70)
at com.evermind._gz.doFilter(.:20)
at
com.formicary.epix.filter.LoginFilter.doFilter(LoginFilter.java:86)
at com.evermind._gz.doFilter(.:20)
at
com.formicary.epix.filter.LoginFilter.doFilter(LoginFilter.java:653)
at com.evermind._gz.doFilter(.:20)
at
com.formicary.epix.filter.RequestFilter.doFilter(RequestFilter.java:261)
at com.evermind._csb._pud(.:379)
at com.evermind._csb._bqc(.:176)
at com.evermind._ax._ltc(.:668)
at com.evermind._ax._ucb(.:193)
at com.evermind._bf.run(.:62)
ERROR [2006-02-15 12:37:58,744] JSP "500.jsp: Transaction was rolled back:
org.hibernate.PersistentObjectException: detached entity passed to persist:
com.formicary.epix.module.message.MessageFolder; nested exception is:
org.hibernate.PersistentObjectException: detached entity passed to persist:
com.formicary.epix.module.message.MessageFolder<p><small><small><pre>javax.ejb.EJBException:
Transaction was rolled back: org.hibernate.PersistentObjectException: detached
entity passed to persist: com.formicary.epix.module.message.MessageFolder; nested exception is: org.hibernate.PersistentObjectException: detached entity passed to
persist:
com.formicary.epix.module.message.MessageFolder
org.hibernate.PersistentObjectException: detached entity passed to
persist: com.formicary.epix.module.message.MessageFolder
at
org.hibernate.event.def.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:79)
at
org.hibernate.event.def.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:38)
at org.hibernate.impl.SessionImpl.firePersist(SessionImpl.java:640)
at org.hibernate.impl.SessionImpl.persist(SessionImpl.java:614)
at org.hibernate.impl.SessionImpl.persist(SessionImpl.java:618)
at
org.hibernate.ejb.AbstractEntityManagerImpl.persist(AbstractEntityManagerImpl.java:127)
at
com.formicary.epix.module.message.MessageModuleBean.createFolder(MessageModuleBean.java:129)
at
MessageModule_StatelessSessionBeanWrapper0.createFolder(MessageModule_StatelessSessionBeanWrapper0.java:1052)
at
com.formicary.epix.actions.message.MessageAction.doAddFolder(MessageAction.java:384)
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:585)
at
webwork.util.InjectionUtils$DefaultInjectionImpl.invoke(InjectionUtils.java:61)
at webwork.util.InjectionUtils.invoke(InjectionUtils.java:52)
at webwork.action.ActionSupport.invokeCommand(ActionSupport.java:417)
at webwork.action.ActionSupport.execute(ActionSupport.java:146)
at
webwork.dispatcher.GenericDispatcher.executeAction(GenericDispatcher.java:132)
at
webwork.dispatcher.ServletDispatcher.service(ServletDispatcher.java:175)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:333)
at com.evermind._ha.doFilter(.:59)
at
com.formicary.epix.filter.SmartURLFilter.doFilter(SmartURLFilter.java:123)
at com.evermind._gz.doFilter(.:16)
at
com.formicary.epix.filter.SmartURLFilter.doFilter(SmartURLFilter.java:63)
at com.evermind._gz.doFilter(.:20)
at
com.formicary.epix.filter.CommunityFilter.doFilter(CommunityFilter.java:336)
at com.evermind._gz.doFilter(.:20)
at
com.formicary.epix.filter.CommunityFilter.doFilter(CommunityFilter.java:336)
at com.evermind._gz.doFilter(.:20)
at
com.opensymphony.module.sitemesh.filter.PageFilter.parsePage(PageFilter.java:119)
at
com.formicary.epix.filter.SitemeshFilter.parsePage(SitemeshFilter.java:27)
at
com.opensymphony.module.sitemesh.filter.PageFilter.doFilter(PageFilter.java:55)
at
com.formicary.epix.filter.ProxyPageFilter.doFilter(ProxyPageFilter.java:37)
at com.evermind._gz.doFilter(.:20)
at
com.formicary.epix.filter.CommunityPrefixFilter.doFilter(CommunityPrefixFilter.java:70)
at com.evermind._gz.doFilter(.:20)
at
com.formicary.epix.filter.LoginFilter.doFilter(LoginFilter.java:86)
at com.evermind._gz.doFilter(.:20)
at
com.formicary.epix.filter.LoginFilter.doFilter(LoginFilter.java:653)
at com.evermind._gz.doFilter(.:20)
at
com.formicary.epix.filter.RequestFilter.doFilter(RequestFilter.java:261)
at com.evermind._csb._pud(.:379)
at com.evermind._csb._bqc(.:176)
at com.evermind._ax._ltc(.:668)
at com.evermind._ax._ucb(.:193)
at com.evermind._bf.run(.:62)
javax.ejb.EJBException: Transaction was rolled back:
org.hibernate.PersistentObjectException: detached entity passed to persist:
com.formicary.epix.module.message.MessageFolder; nested exception is:
org.hibernate.PersistentObjectException:
detached entity passed to persist: com.formicary.epix.module.message.MessageFolder
at
MessageModule_StatelessSessionBeanWrapper0.createFolder(MessageModule_StatelessSessionBeanWrapper0.java:1087)
at
com.formicary.epix.actions.message.MessageAction.doAddFolder(MessageAction.java:384)
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:585)
at
webwork.util.InjectionUtils$DefaultInjectionImpl.invoke(InjectionUtils.java:61)
at webwork.util.InjectionUtils.invoke(InjectionUtils.java:52)
at webwork.action.ActionSupport.invokeCommand(ActionSupport.java:417)
at webwork.action.ActionSupport.execute(ActionSupport.java:146)
at
webwork.dispatcher.GenericDispatcher.executeAction(GenericDispatcher.java:132)
at
webwork.dispatcher.ServletDispatcher.service(ServletDispatcher.java:175)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:333)
at com.evermind._ha.doFilter(.:59)
at
com.formicary.epix.filter.SmartURLFilter.doFilter(SmartURLFilter.java:123)
at com.evermind._gz.doFilter(.:16)
at
com.formicary.epix.filter.SmartURLFilter.doFilter(SmartURLFilter.java:63)
at com.evermind._gz.doFilter(.:20)
at
com.formicary.epix.filter.CommunityFilter.doFilter(CommunityFilter.java:336)
at com.evermind._gz.doFilter(.:20)
at
com.formicary.epix.filter.CommunityFilter.doFilter(CommunityFilter.java:336)
at com.evermind._gz.doFilter(.:20)
at
com.opensymphony.module.sitemesh.filter.PageFilter.parsePage(PageFilter.java:119)
at
com.formicary.epix.filter.SitemeshFilter.parsePage(SitemeshFilter.java:27)
at
com.opensymphony.module.sitemesh.filter.PageFilter.doFilter(PageFilter.java:55)
at
com.formicary.epix.filter.ProxyPageFilter.doFilter(ProxyPageFilter.java:37)
at com.evermind._gz.doFilter(.:20)
at
com.formicary.epix.filter.CommunityPrefixFilter.doFilter(CommunityPrefixFilter.java:70)
at com.evermind._gz.doFilter(.:20)
at
com.formicary.epix.filter.LoginFilter.doFilter(LoginFilter.java:86)
at com.evermind._gz.doFilter(.:20)
at
com.formicary.epix.filter.LoginFilter.doFilter(LoginFilter.java:653)
at com.evermind._gz.doFilter(.:20)
at
com.formicary.epix.filter.RequestFilter.doFilter(RequestFilter.java:261)
at com.evermind._csb._pud(.:379)
at com.evermind._csb._bqc(.:176)
at com.evermind._ax._ltc(.:668)
at com.evermind._ax._ucb(.:193)
at com.evermind._bf.run(.:62)
</pre></small></small></p>"


Top
 Profile  
 
 Post subject:
PostPosted: Thu Feb 16, 2006 11:25 am 
Hibernate Team
Hibernate Team

Joined: Sun Sep 14, 2003 3:54 am
Posts: 7256
Location: Paris, France
From what I can see your prepersist methond is not yet called.
You try to mass a detached entity to persist which is not allowed.

_________________
Emmanuel


Top
 Profile  
 
 Post subject:
PostPosted: Fri Feb 17, 2006 12:13 pm 
Newbie

Joined: Wed Feb 15, 2006 11:11 am
Posts: 2
Location: London
Emmanuel,

The @PrePersist annotated method is definitely being called - it is being called from a call to EntityManager.persist() with a new entity, a process which successfully persists new entities if, in this example, they have their name field instantiated appropriately.

Perhaps what is occurring is the @PrePersist annotated method is called, the ValidateException thrown, it is caught within Hibernate (DefaultPersistEventListener for example), which is detaching the entity and silently swallowing the exception, then an attempt is made to persist the detached entity, causing the exception seen above.

I've tested again locally, outputting a log statement directly before the throw new ValidateException(..) and the method is indeed being called.


Top
 Profile  
 
Display posts from previous:  Sort by  
Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 3 posts ] 

All times are UTC - 5 hours [ DST ]


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum

Search for:
© Copyright 2014, Red Hat Inc. All rights reserved. JBoss and Hibernate are registered trademarks and servicemarks of Red Hat, Inc.