Issue
I realize that this question has been asked many times on StackOverflow, and I've read through many of these questions which were asked from 13 years ago to 3 months ago, and none of these have answered my question. I am working on a non-Spring application, and we are going from Hibernate 3.x to Hibernate 5.6.0.Final at this time. I can tell you since we are not using Spring to control our persistence and session management, this is code that was written by us. So, let me start with our stack trace which is quite long:
Message: org.hibernate.HibernateException: Found shared references to a collection: com.myproject.server.model.user.User.roles
javax.persistence.PersistenceException: org.hibernate.HibernateException: Found shared references to a collection: com.myproject.server.model.user.User.roles
at org.hibernate.internal.ExceptionConverterImpl.convert(ExceptionConverterImpl.java:154)
at org.hibernate.internal.ExceptionConverterImpl.convert(ExceptionConverterImpl.java:181)
at org.hibernate.internal.ExceptionConverterImpl.convert(ExceptionConverterImpl.java:188)
at org.hibernate.internal.SessionImpl.doFlush(SessionImpl.java:1406)
at org.hibernate.internal.SessionImpl.flush(SessionImpl.java:1389)
at com.myproject.server.services.db.Transaction.commit(Transaction.java:51)
at com.myproject.server.services.db.service.PersistenceManager.commitTransactionIfOpen(PersistenceManager.java:156)
at com.myproject.server.services.db.service.DataService.save(DataService.java:300)
at com.myproject.server.services.db.service.DataService.save(DataService.java:241)
at com.myproject.server.rest.user.LoginResourceImpl.acceptEula(LoginResourceImpl.java:113)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:566)
at com.sun.jersey.spi.container.JavaMethodInvokerFactory$1.invoke(JavaMethodInvokerFactory.java:60)
at com.sun.jersey.server.impl.model.method.dispatch.AbstractResourceMethodDispatchProvider$TypeOutInvoker._dispatch(AbstractResourceMethodDispatchProvider.java:185)
at com.sun.jersey.server.impl.model.method.dispatch.ResourceJavaMethodDispatcher.dispatch(ResourceJavaMethodDispatcher.java:75)
at com.sun.jersey.server.impl.uri.rules.HttpMethodRule.accept(HttpMethodRule.java:302)
at com.sun.jersey.server.impl.uri.rules.RightHandPathRule.accept(RightHandPathRule.java:147)
at com.sun.jersey.server.impl.uri.rules.ResourceClassRule.accept(ResourceClassRule.java:108)
at com.sun.jersey.server.impl.uri.rules.RightHandPathRule.accept(RightHandPathRule.java:147)
at com.sun.jersey.server.impl.uri.rules.RootResourceClassesRule.accept(RootResourceClassesRule.java:84)
at com.sun.jersey.server.impl.application.WebApplicationImpl._handleRequest(WebApplicationImpl.java:1542)
at com.sun.jersey.server.impl.application.WebApplicationImpl._handleRequest(WebApplicationImpl.java:1473)
at com.sun.jersey.server.impl.application.WebApplicationImpl.handleRequest(WebApplicationImpl.java:1419)
at com.sun.jersey.server.impl.application.WebApplicationImpl.handleRequest(WebApplicationImpl.java:1409)
at com.sun.jersey.spi.container.servlet.WebComponent.service(WebComponent.java:409)
at com.sun.jersey.spi.container.servlet.ServletContainer.service(ServletContainer.java:558)
at com.sun.jersey.spi.container.servlet.ServletContainer.service(ServletContainer.java:733)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:729)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:230)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:165)
at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:192)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:165)
at com.myproject.server.log.AddLogRequestIdFilter.doFilter(AddLogRequestIdFilter.java:38)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:192)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:165)
at com.myproject.server.log.AddLogContextFilter.doFilter(AddLogContextFilter.java:61)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:192)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:165)
at com.myproject.server.services.user.SessionSetupFilter.doFilter(SessionSetupFilter.java:54)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:192)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:165)
at com.myproject.server.services.db.DataLayerThreadFilter.doFilter(DataLayerThreadFilter.java:79)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:192)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:165)
at com.myproject.server.services.security.CrossOriginFilter.doFilter(CrossOriginFilter.java:68)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:192)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:165)
at org.tuckey.web.filters.urlrewrite.RuleChain.handleRewrite(RuleChain.java:176)
at org.tuckey.web.filters.urlrewrite.RuleChain.doRules(RuleChain.java:145)
at org.tuckey.web.filters.urlrewrite.UrlRewriter.processRequest(UrlRewriter.java:92)
at org.tuckey.web.filters.urlrewrite.UrlRewriteFilter.doFilter(UrlRewriteFilter.java:394)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:192)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:165)
at org.apache.shiro.web.servlet.AbstractShiroFilter.executeChain(AbstractShiroFilter.java:449)
at org.apache.shiro.web.servlet.AbstractShiroFilter$1.call(AbstractShiroFilter.java:365)
at org.apache.shiro.subject.support.SubjectCallable.doCall(SubjectCallable.java:90)
at org.apache.shiro.subject.support.SubjectCallable.call(SubjectCallable.java:83)
at org.apache.shiro.subject.support.DelegatingSubject.execute(DelegatingSubject.java:383)
at org.apache.shiro.web.servlet.AbstractShiroFilter.doFilterInternal(AbstractShiroFilter.java:362)
at org.apache.shiro.web.servlet.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:125)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:192)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:165)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:198)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:108)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:522)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:140)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:79)
at org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:620)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:87)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:349)
at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:1110)
at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66)
at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:785)
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1425)
at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
at java.base/java.lang.Thread.run(Thread.java:829)
Caused by: org.hibernate.HibernateException: Found shared references to a collection: com.myproject.server.model.user.User.roles
at org.hibernate.engine.internal.Collections.processReachableCollection(Collections.java:188)
at org.hibernate.event.internal.FlushVisitor.processCollection(FlushVisitor.java:53)
at org.hibernate.event.internal.AbstractVisitor.processValue(AbstractVisitor.java:104)
at org.hibernate.event.internal.AbstractVisitor.processValue(AbstractVisitor.java:65)
at org.hibernate.event.internal.AbstractVisitor.processEntityPropertyValues(AbstractVisitor.java:59)
at org.hibernate.event.internal.DefaultFlushEntityEventListener.onFlushEntity(DefaultFlushEntityEventListener.java:183)
at com.myproject.server.services.db.eventlisteners.debug.DebugFlushEntityEventListener.onFlushEntity(DebugFlushEntityEventListener.java:25)
at org.hibernate.event.service.internal.EventListenerGroupImpl.fireEventOnEachListener(EventListenerGroupImpl.java:107)
at org.hibernate.event.internal.AbstractFlushingEventListener.flushEntities(AbstractFlushingEventListener.java:229)
at org.hibernate.event.internal.AbstractFlushingEventListener.flushEverythingToExecutions(AbstractFlushingEventListener.java:93)
at org.hibernate.event.internal.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:39)
at org.hibernate.event.service.internal.EventListenerGroupImpl.fireEventOnEachListener(EventListenerGroupImpl.java:107)
at org.hibernate.internal.SessionImpl.doFlush(SessionImpl.java:1402)
... 78 more
The User.hbm.xml file looks like this:
<hibernate-mapping package="com.ekotrope.server.model.user">
<class name="User" table="user">
<id name="id" column="id">
<generator class="increment" />
</id>
<bag name="roles" table="roles" cascade = "all,delete-orphan" lazy="false">
<key column="userId" not-null="false" />
<element type="com.ekotrope.server.model.user.RoleUserType"/>
</bag>
<set name="permissions" table="user_permission" cascade="all" lazy="false">
<key column="userId" not-null="true"/>
<element column="permission" not-null="true" type="java.lang.String" />
</set>
<property name="password" not-null="true"/>
<property name="name" not-null="true"/>
<property name="username" not-null="true" unique="true"/>
<property name="email" not-null="true"/>
<property name="lastUpdateAt" type="timestamp" not-null="true"/>
</class>
</hibernate-mapping>
I know we're using Hibernate 5, but we're not quite ready to jump to completely annotated classes yet, but that is what we want to do in a near future sprint.
We definitely have some servlet filters in our chain that open to the database user and we can get that successfully. We are definitely tracking the count of instances within the JVM and the session and we think we only have ONE User. We are using Eclipse and when we right-click on a Variable in debug mode we can see the instance count, we can see all the instances, and we can see the references.
The collection of roles is EAGER loaded from the database and we can see we have 2 roles, and we aren't touching the roles at all. But when we save to the database, or even just do a session flush, then we come to this error.
So, we've tried to eliminate a lot of issues by checking painfully what is in the session, and making sure we only have the one instance, and we still get this error. We are in the Hibernate code to see what is causing this error. We know we have triggered the isReached part and that is throwing the exception. So, if we can figure out why our session has more than once instance, then we can fix that in our code. If any one has any tips for us or suggestions we can try, that would be helpful.
Solution
I figured this one out, but it took quite a bit of time. As I added more logging into a variety of methods in our company code (not the hibernate code), I found that somehow we were jumping into the hibernate code twice.
In the company I was working at, we had some Hibernate Listeners, and this code was rather old. I actually posted more of this on the Hibernate support boards. With the help of the Hibernate Developers, I found a much better way to have code for the Listeners, the approved way, and when I did that, it solved our issue.
We were able to write code to the database, but with the listeners making sure we only jumped into the Hibernate code ONCE, not TWICE. This made the issue go away. I will come back and update this story when I have more details.
Answered By - tjholmes66
Answer Checked By - David Marino (JavaFixing Volunteer)