0

I used so far classic Hibernate with the "Session" Object and not using the JPA EntityManager. Now I introduced the JPA Listener/callback support by activating the service "org.hibernate.jpa.event.spi.JpaIntegrator" in my META-INF.

After that I get during the call "session.saveOrUpdate()" this error. The Listener I added was on another class and also if I remove there the "EntityListeners" JPA annotation, the error still appears.

 java.lang.IllegalArgumentException: Removing a detached instance Attribute#233800
    at org.hibernate.jpa.event.internal.core.JpaDeleteEventListener.performDetachedEntityDeletionCheck(JpaDeleteEventListener.java:69)

without this JPA Listener activation it was working fine.

My code is removing an object from the parent (detached - outside of a transaction), and then tries to save the parent with a new transaction. The child is owned by the parent and all changes should get cascaded? So what I need to do or is this a Bug of Hibernate?

I am using Hibernate v4.3.10

The Listener I added was on another class and also if I remove there the annotation, the error still appears.

Executed Code

    Model model = modelDAO.getModelByCode("1234567");
    model.removeAttribute("Description");
    modelDAO.saveModel(model);  

Implementation of the ModelDAO

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

    protected void beginTransaction() {
      Session session = getSession();
      Transaction transaction = session.getTransaction();
      if (!transaction.isActive()) {
          transaction.begin();
      }
    }

    protected void handleTransaction() {
      if (!bulkHandling) {
          commitTransaction();
      }
    }

    protected void commitTransaction() {
       Session session = getSession();
       Transaction transaction = session.getTransaction();
       if (transaction.isActive()) {
           transaction.commit();
       }
    }

    protected void saveObject(Object obj) {
    if(obj != null) {
        try {
            Session session = getSession();
            beginTransaction();
            if (!session.contains(obj)) {
                session.saveOrUpdate(obj);
            } 
            handleTransaction();
        } catch (Exception ex) {
            logger.error(ex.getMessage(),ex);
            rollbackTransaction();
            throw new HandledOneERPException(ex);
        }
    }
  }

Model & Mapping

  @Entity
  public class Model extends AbstractERPEntity implements Translateable {

    @OneToMany(cascade = CascadeType.ALL, fetch=FetchType.LAZY, orphanRemoval=true)
    @JoinTable(name = "model_attributes", joinColumns = @JoinColumn(name = "model_id"), inverseJoinColumns = @JoinColumn(name = "attribute_id"))
    @MapKey(name = "name")
    private Map<String, Attribute<?>> attributes = new HashMap<String, Attribute<?>>();

Full Stack Trace

 java.lang.IllegalArgumentException: Removing a detached instance     ch.megloff.one.erp.model.attribute.Attribute#233800
  at org.hibernate.jpa.event.internal.core.JpaDeleteEventListener.performDetachedEntityDeletionCheck(JpaDeleteEventListener.java:69) ~[hibernate-entitymanager-4.3.10.Final.jar:4.3.10.Final]
  at org.hibernate.event.internal.DefaultDeleteEventListener.onDelete(DefaultDeleteEventListener.java:106) ~[hibernate-core-4.3.10.Final.jar:4.3.10.Final]
  at org.hibernate.internal.SessionImpl.fireDelete(SessionImpl.java:965) ~[hibernate-core-4.3.10.Final.jar:4.3.10.Final]
  at org.hibernate.internal.SessionImpl.delete(SessionImpl.java:909) ~[hibernate-core-4.3.10.Final.jar:4.3.10.Final]
  at org.hibernate.engine.internal.Cascade.deleteOrphans(Cascade.java:437) ~[hibernate-core-4.3.10.Final.jar:4.3.10.Final]
  at org.hibernate.engine.internal.Cascade.cascadeCollectionElements(Cascade.java:410) ~[hibernate-core-4.3.10.Final.jar:4.3.10.Final]
  at org.hibernate.engine.internal.Cascade.cascadeCollection(Cascade.java:319) ~[hibernate-core-4.3.10.Final.jar:4.3.10.Final]
  at org.hibernate.engine.internal.Cascade.cascadeAssociation(Cascade.java:296) ~[hibernate-core-4.3.10.Final.jar:4.3.10.Final]
  at org.hibernate.engine.internal.Cascade.cascadeProperty(Cascade.java:161) ~[hibernate-core-4.3.10.Final.jar:4.3.10.Final]
  at org.hibernate.engine.internal.Cascade.cascade(Cascade.java:118) ~[hibernate-core-4.3.10.Final.jar:4.3.10.Final]
  at org.hibernate.engine.internal.Cascade.cascade(Cascade.java:86) ~[hibernate-core-4.3.10.Final.jar:4.3.10.Final]
  at org.hibernate.event.internal.DefaultSaveOrUpdateEventListener.cascadeOnUpdate(DefaultSaveOrUpdateEventListener.java:375) ~[hibernate-core-4.3.10.Final.jar:4.3.10.Final]
  at org.hibernate.event.internal.DefaultSaveOrUpdateEventListener.performUpdate(DefaultSaveOrUpdateEventListener.java:349) ~[hibernate-core-4.3.10.Final.jar:4.3.10.Final]
  at org.hibernate.event.internal.DefaultSaveOrUpdateEventListener.entityIsDetached(DefaultSaveOrUpdateEventListener.java:244) ~[hibernate-core-4.3.10.Final.jar:4.3.10.Final]
  at org.hibernate.event.internal.DefaultSaveOrUpdateEventListener.performSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:109) ~[hibernate-core-4.3.10.Final.jar:4.3.10.Final]
  at org.hibernate.event.internal.DefaultSaveOrUpdateEventListener.onSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:90) ~[hibernate-core-4.3.10.Final.jar:4.3.10.Final]
  at org.hibernate.internal.SessionImpl.fireSaveOrUpdate(SessionImpl.java:684) ~[hibernate-core-4.3.10.Final.jar:4.3.10.Final]
  at org.hibernate.internal.SessionImpl.saveOrUpdate(SessionImpl.java:676) ~[hibernate-core-4.3.10.Final.jar:4.3.10.Final]
  at org.hibernate.internal.SessionImpl.saveOrUpdate(SessionImpl.java:671) ~[hibernate-core-4.3.10.Final.jar:4.3.10.Final]
 at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[?:1.8.0_65]
  at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[?:1.8.0_65]
  at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[?:1.8.0_65]
  at java.lang.reflect.Method.invoke(Method.java:497) ~[?:1.8.0_65]
  at org.hibernate.context.internal.ThreadLocalSessionContext$TransactionProtectionWrapper.invoke(ThreadLocalSessionContext.java:356) ~[hibernate-core-4.3.10.Final.jar:4.3.10.Final]
  at com.sun.proxy.$Proxy70.saveOrUpdate(Unknown Source) ~[?:?]
  at ch.megloff.common.dao.AbstractHibernateDAO.saveObject(AbstractHibernateDAO.java:261) [classes/:?]
Community
  • 1
  • 1
megloff
  • 1,400
  • 4
  • 27
  • 44
  • 1
    Having had to solve a couple dozen of similar problems myself I can assure you it is not a bug in Hibernate, it is a bug in your understanding of how Hibernate works. And in this case it looks to me, but I can't be sure because there is not nearly enough code, like you're trying to do the delete outside of a transaction. – Gimby Mar 10 '16 at 07:31
  • but why it has been previously working without the JPA Listener support activiation? In which area of source code you are interested in? – megloff Mar 10 '16 at 13:35
  • I spent some hours but I got it not working. After studying this [link](http://stackoverflow.com/questions/912659/what-is-the-proper-way-to-re-attach-detached-objects-in-hibernate/3683370) and [link](https://docs.jboss.org/hibernate/entitymanager/3.6/reference/en/html/objectstate.html#objectstate-transitive) I came to the conclusion that this is mostlikely a bug of Hibernate. A solution for me is rather using the JPA callbacks the Hibernate Event Lister [link](http://stackoverflow.com/questions/8616146/eventlisteners-using-hibernate-4-0-with-spring-3-1-0-release) – megloff Mar 10 '16 at 18:44

1 Answers1

0

I spent some hours but I got it not working with the JPA Listener "org.hibernate.jpa.event.spi.JpaIntegrator". After studying the following links

I came to the conclusion that this is mostlikely a bug of Hibernate, because "saveOrUpdate()" should exaclty handle such situations which it also does if I not use the "JpaIntegrator" stuff. I tried also with Hibernate 4.3.11, same issue.

A solution for me was rather using the special JPA Listener activation the Hibernate Event Listener

e.g.

@Component
@Log4j2
public class HibernateEventListener implements PostCommitDeleteEventListener {

@Autowired
@Qualifier("hibernateOneERPSessionFactory")
private SessionFactory sessionFactory;

@Autowired
private ThreadPoolTaskExecutor taskExecutor;

@Autowired
private TranslationDAO translationDAO;

@PostConstruct
public void registerListeners() {

    taskExecutor.setWaitForTasksToCompleteOnShutdown(true);
    taskExecutor.setAwaitTerminationSeconds(Integer.MAX_VALUE); 

   final EventListenerRegistry registry = ((SessionFactoryImpl) sessionFactory)
            .getServiceRegistry().getService(EventListenerRegistry.class);
    registry.appendListeners(EventType.POST_COMMIT_DELETE, this);
}

@Override
public void onPostDelete(PostDeleteEvent event) {
    Object obj = event.getEntity();
    if(obj instanceof Translateable) {
        Translateable translateable = (Translateable)obj;
        if (translateable.hasTranslation()) {
            Runnable task = new Runnable() {
                 public void run()  {
                    translationDAO.deleteUnusedTranslations();
                 }
            };
            taskExecutor.initialize();
            taskExecutor.execute(task);
            taskExecutor.shutdown();
        }
    }
}
}
Community
  • 1
  • 1
megloff
  • 1,400
  • 4
  • 27
  • 44