13 Replies Latest reply on Apr 12, 2018 6:46 AM by ankurdoshi01

    NonUniqueObjectException on JPA persist

    arthur.kalm

      Hello everyone,

      I'm getting a strange Envers exception every time I call JPA's persist method (no exception when merging). The exception is the following:

      org.hibernate.NonUniqueObjectException: a different object with the same identifier value was already associated with the session: [com.sinai.credentialing.domain.StaffMember_versions#{_revision=DefaultRevisionEntity(id = 1, revisionDate = Feb 11, 2009 10:21:41 AM), id=1}]
      


      Even though this exception occurs, Envers and Hibernate still work fine, i.e. everything gets stored in the database.

      The full stack trace follows:

      WARN] exception calling user Synchronization
      org.hibernate.NonUniqueObjectException: a different object with the same identifier value was already associated with the session: [com.sinai.credentialing.domain.StaffMember_versions#{_revision=DefaultRevisionEntity(id = 1, revisionDate = Feb 11, 2009 10:21:41 AM), id=1}]
       at org.hibernate.event.def.AbstractSaveEventListener.performSave(AbstractSaveEventListener.java:168)
       at org.hibernate.event.def.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:121)
       at org.hibernate.ejb.event.EJB3SaveEventListener.saveWithGeneratedId(EJB3SaveEventListener.java:43)
       at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.saveWithGeneratedOrRequestedId(DefaultSaveOrUpdateEventListener.java:187)
       at org.hibernate.event.def.DefaultSaveEventListener.saveWithGeneratedOrRequestedId(DefaultSaveEventListener.java:33)
       at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.entityIsTransient(DefaultSaveOrUpdateEventListener.java:172)
       at org.hibernate.event.def.DefaultSaveEventListener.performSaveOrUpdate(DefaultSaveEventListener.java:27)
       at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.onSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:70)
       at org.hibernate.impl.SessionImpl.fireSave(SessionImpl.java:535)
       at org.hibernate.impl.SessionImpl.save(SessionImpl.java:523)
       at org.jboss.envers.synchronization.work.CollectionChangeWorkUnit.perform(CollectionChangeWorkUnit.java:54)
       at org.jboss.envers.synchronization.VersionsSync.executeInSession(VersionsSync.java:120)
       at org.jboss.envers.synchronization.VersionsSync.beforeCompletion(VersionsSync.java:144)
       at org.hibernate.transaction.JDBCTransaction.notifyLocalSynchsBeforeTransactionCompletion(JDBCTransaction.java:228)
       at org.hibernate.transaction.JDBCTransaction.commit(JDBCTransaction.java:109)
       at org.hibernate.ejb.TransactionImpl.commit(TransactionImpl.java:54)
       at org.springframework.orm.jpa.JpaTransactionManager.doCommit(JpaTransactionManager.java:456)
       at org.springframework.transaction.support.AbstractPlatformTransactionManager.processCommit(AbstractPlatformTransactionManager.java:732)
       at org.springframework.transaction.support.AbstractPlatformTransactionManager.commit(AbstractPlatformTransactionManager.java:701)
       at org.springframework.transaction.interceptor.TransactionAspectSupport.commitTransactionAfterReturning(TransactionAspectSupport.java:321)
       at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:116)
       at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:171)
       at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:204)
       at $Proxy33.saveStaffMember(Unknown Source)
       at com.sinai.credentialing.server.service.StaffMemberServiceImpl.store(StaffMemberServiceImpl.java:60)
       at com.sinai.credentialing.server.service.MidwifeServiceImpl.saveMidwife(MidwifeServiceImpl.java:79)
       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 com.google.gwt.user.server.rpc.RPC.invokeAndEncodeResponse(RPC.java:527)
       at com.google.gwt.user.server.rpc.RPC.invokeAndEncodeResponse(RPC.java:477)
       at com.sinai.credentialing.server.gwt.GwtRpcEndPointHandlerAdapter.processCall(GwtRpcEndPointHandlerAdapter.java:121)
       at com.google.gwt.user.server.rpc.RemoteServiceServlet.doPost(RemoteServiceServlet.java:86)
       at com.sinai.credentialing.server.gwt.GwtRpcEndPointHandlerAdapter.handle(GwtRpcEndPointHandlerAdapter.java:74)
       at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:875)
       at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:807)
       at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:571)
       at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:511)
       at javax.servlet.http.HttpServlet.service(HttpServlet.java:709)
       at javax.servlet.http.HttpServlet.service(HttpServlet.java:802)
       at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:237)
       at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:157)
       at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:214)
       at org.apache.catalina.core.StandardValveContext.invokeNext(StandardValveContext.java:104)
       at org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:520)
       at org.apache.catalina.core.StandardContextValve.invokeInternal(StandardContextValve.java:198)
       at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:152)
       at org.apache.catalina.core.StandardValveContext.invokeNext(StandardValveContext.java:104)
       at org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:520)
       at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:137)
       at org.apache.catalina.core.StandardValveContext.invokeNext(StandardValveContext.java:104)
       at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:118)
       at org.apache.catalina.core.StandardValveContext.invokeNext(StandardValveContext.java:102)
       at org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:520)
       at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109)
       at org.apache.catalina.core.StandardValveContext.invokeNext(StandardValveContext.java:104)
       at org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:520)
       at org.apache.catalina.core.ContainerBase.invoke(ContainerBase.java:929)
       at org.apache.coyote.tomcat5.CoyoteAdapter.service(CoyoteAdapter.java:160)
       at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:799)
       at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.processConnection(Http11Protocol.java:705)
       at org.apache.tomcat.util.net.TcpWorkerThread.runIt(PoolTcpEndpoint.java:577)
       at org.apache.tomcat.util.threads.ThreadPool$ControlRunnable.run(ThreadPool.java:683)
       at java.lang.Thread.run(Thread.java:613)
      



      Thank you in advance for any help you can provide.

      Best regards,
      Arthur Kalmenson

        • 1. Re: NonUniqueObjectException on JPA persist
          adamw

          Hello,

          this looks very strange ... could you maybe create a jira bug with a testcase?

          --
          Adam

          • 2. Re: NonUniqueObjectException on JPA persist
            adamw

            Hello,

            I've encountered something similar today. Do you use a persistent collection and do your changes to the entities change the hashCode of the objects in the collection?

            --
            Adam

            • 3. Re: NonUniqueObjectException on JPA persist
              arthur.kalm

              Hello Adam,

              We do use Lists (which become PersistentBags) and the objects inside the list are mutable (thereby changing the hashCode).

              Best regards,
              Arthur Kalmenson

              • 4. Re: NonUniqueObjectException on JPA persist
                adamw

                Hello,

                so it's something else ... persistent bags don't depend on hash code. Did you manage to create a test case which reproduces the problem? Can you post it/attach it to JIRA?

                Thanks,
                Adam

                • 5. Re: NonUniqueObjectException on JPA persist
                  arthur.kalm

                  Hi Adam,

                  Sorry, I haven't had a chance to make a test case to reproduce it. I'll try to do that this weekend if I get the chance.

                  • 6. Re: NonUniqueObjectException on JPA persist
                    arthur.kalm

                    OK, so I've tried upgrading to Hibernate 3.3 and changing the Envers version to the Hibernate 3.3 one, it hasn't helped. I think that this exception is preventing Envers from working correctly.

                    If I have an existing record, and I modify and save it, shouldn't Envers copy the version I'm about to update to the _version table? It only does this after I save the object twice, and then only copies the latest change to the _version table so the latest record in the _version table is the same one as the non _version table.

                    • 7. Re: NonUniqueObjectException on JPA persist
                      adamw

                      Hello,

                      what you describe is how things should be ... where's the exception? If you modify a record, Envers saves it also in the audit tables, and does that only for the latest change in the transaction.

                      Adam

                      • 8. Re: NonUniqueObjectException on JPA persist
                        arthur.kalm

                        Is that how Envers is suppose to work? On the initial save, nothing is copied to the audit table, that's probably not the expected behavior.

                        The exception is the same one I noted above.

                        • 9. Re: NonUniqueObjectException on JPA persist
                          adamw

                          Hello,

                          on the initial save, a record should be copied to the audit table. So something is certainly wrong. But I can't say much more without a testcase :)

                          Adam

                          • 10. Re: NonUniqueObjectException on JPA persist
                            arthur.kalm

                            Hehe, sorry Adam. I'm going to have to solve this problem in the next few days so I'll try to post something that reproduces the problem. Thanks again.

                            • 11. Re: NonUniqueObjectException on JPA persist
                              arthur.kalm

                              Hi Adam,

                              I've tried the latest Envers version and the exception has gone away and the auditing seems to be working correctly when run live. However, I can't seem to get a test case to pass. My test case is a Spring based test and looks as follows:

                              @ContextConfiguration(locations = { "classpath:WEB-INF/applicationContext.xml",
                               "classpath:WEB-INF/applicationContext-gwt.xml",
                               "classpath:WEB-INF/applicationContext-search.xml",
                               "classpath:WEB-INF/testApplicationContext-security.xml",
                               "classpath:WEB-INF/testApplicationContext-search.xml",
                               "classpath:WEB-INF/testApplicationContext.xml" })
                              @TransactionConfiguration(defaultRollback = false)
                              public class EnversTest extends AbstractTransactionalTestNGSpringContextTests {
                              
                               /**
                               * The {@link StaffMemberDao} we will use for testing.
                               */
                               @Autowired
                               private StaffMemberDao staffMemberDao;
                              
                               /**
                               * The {@link EntityManager} that's currently in use. We use it to remove
                               * all attached entities.
                               */
                               @PersistenceContext
                               private EntityManager entityManager;
                              
                               /**
                               * Modifing a simple midwife.
                               */
                               @Test
                               public void simpleMidwifeModification() {
                               Midwife midwife = new Midwife();
                               midwife.setDemographicInfo(new DemographicInfo("Mr.", "Test", "",
                               "Blah", "Male", Date.valueOf("1960-02-04")));
                               StaffMember savedMidwife = staffMemberDao.saveStaffMember(midwife);
                               clearEntityManager();
                              
                               DemographicInfo demographicInfo = savedMidwife.getDemographicInfo();
                               demographicInfo.setFirstName("Testering");
                               staffMemberDao.saveStaffMember(savedMidwife);
                               clearEntityManager();
                              
                               // get the first revision of the DemographicInfo
                               AuditReader reader = AuditReaderFactory.get(entityManager);
                               DemographicInfo firstDemographicInfo = reader.find(
                               DemographicInfo.class, demographicInfo.getId(), 1);
                              
                               // recreate the original one.
                               DemographicInfo original = new DemographicInfo("Mr.",
                               "Test", "", "Blah", "Male", Date.valueOf("1960-02-04"));
                               original.setId(demographicInfo.getId());
                              
                               // check them.
                               Assert.assertEquals(firstDemographicInfo, original);
                               }
                              
                               /**
                               * Flushes the EntityManager (writing to the database) and then clears it.
                               */
                               private void clearEntityManager() {
                               // empty the entity manager.
                               entityManager.flush();
                               entityManager.clear();
                               }
                              }
                              


                              Thanks again!

                              Best regards,

                              • 12. Re: NonUniqueObjectException on JPA persist
                                adamw

                                Hello,

                                Good that the weird exception went away :)

                                The test case fails because you don't commit the transaction before doing the check. The information in the audit tables is written only when a transaction is commited - only then, the final content of the new data is known.

                                --
                                Adam

                                • 13. Re: NonUniqueObjectException on JPA persist
                                  ankurdoshi01

                                  Hi Adam,

                                  We are also facing similar issue with same exception as mentioned above. This is happening when we are removing data from the entity and then inserting data into same entity in same transaction.

                                  The strange thing is that when we are running the above operations without "Envers" it is working perfectly but when running it with Envers it gives the above mentioned exception.

                                  We are using hibernate Envers version: 4.2.7.Final.

                                  Did we get any solution apart from going towards latest Envers version?