Hi,
under certain circumstances I get a java.util.ConcurrentModificationException from SessionImpl.getEntityName(). It occures only, when I call getEntityName() on an entity that has lazy associations. As you can see in the stacktrace the exception occurs in PersistenceContext.containsProxy(), where the proxy checking and lazy-initializer-fetching happens. The problem seems to be that if the lazy association is being loaded during that call, which definitely seems to happen in my case, it modifies the PersistenceContext's proxiesByKey map. During the iteration the modification is being discovered and accordingly the exception is being thrown.
The code involved is a lot, so I it's hard for me to separate the problem code from the rest, since there's a whole meta model around the code involved. What I can offer is a patch for the SessionImpl which definitely solved the problem for me. I ran the Hibernate test suites and all seemed to be well with it except the query- and ANTLR-involving ones which somehow don't want to work for me. The patch is inspired by the code in SessionImpl.getIdentifier() which does a similar thing. The following version of SessionImpl.getEntityName() seems to solve the problem:
Code:
public String getEntityName(Object object) {
if (object instanceof HibernateProxy) {
LazyInitializer li = ((HibernateProxy) object).getHibernateLazyInitializer();
if ( li.getSession() != this ) {
throw new TransientObjectException( "The proxy was not associated with this session" );
}
object = li.getImplementation();
}
EntityEntry entry = persistenceContext.getEntry(object);
if (entry==null) throwTransientObjectException(object);
return entry.getPersister().getEntityName();
}
I'm using this patched version of SessionImpl and everything is working as it's supposed to. If I'm overseeing something here, please tell me, but it looks to me as if it does the same as the original code of getEntityName().
Cheers, Mathias
Hibernate version: 3.0.5
Full stack trace of any exception that occurs:Code:
java.util.ConcurrentModificationException
at org.apache.commons.collections.ReferenceMap$EntryIterator.checkMod(Unknown Source)
at org.apache.commons.collections.ReferenceMap$EntryIterator.hasNext(Unknown Source)
at java.util.AbstractCollection.contains(AbstractCollection.java:99)
at org.hibernate.engine.PersistenceContext.containsProxy(PersistenceContext.java:468)
at org.hibernate.impl.SessionImpl.getEntityName(SessionImpl.java:1449)
at de.asdis.acm.persistence.support.hibernate.HibernatePersistenceManager.getOid(HibernatePersistenceManager.java:116)
at de.asdis.acm.persistence.support.hibernate.HibernatePersistenceManager.getObjectById(HibernatePersistenceManager.java:207)
at de.asdis.acm.api.tools.SoftwareTools.findSoftwareBO(SoftwareTools.java:113)
at de.asdis.acm.api.tools.SoftwareTools.createSoftwarePackage(SoftwareTools.java:499)
at de.asdis.acm.api.ejb.ObjectManagerServiceBean.createSoftwarePackage(ObjectManagerServiceBean.java:497)
at sun.reflect.GeneratedMethodAccessor382.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:324)
at org.jboss.invocation.Invocation.performCall(Invocation.java:345)
at org.jboss.ejb.StatelessSessionContainer$ContainerInterceptor.invoke(StatelessSessionContainer.java:214)
at org.jboss.resource.connectionmanager.CachedConnectionInterceptor.invoke(CachedConnectionInterceptor.java:185)
at org.jboss.ejb.plugins.StatelessSessionInstanceInterceptor.invoke(StatelessSessionInstanceInterceptor.java:130)
at org.jboss.webservice.server.ServiceEndpointInterceptor.invoke(ServiceEndpointInterceptor.java:51)
at org.jboss.ejb.plugins.CallValidationInterceptor.invoke(CallValidationInterceptor.java:48)
at org.jboss.ejb.plugins.AbstractTxInterceptor.invokeNext(AbstractTxInterceptor.java:105)
at org.jboss.ejb.plugins.TxInterceptorCMT.runWithTransactions(TxInterceptorCMT.java:335)
at org.jboss.ejb.plugins.TxInterceptorCMT.invoke(TxInterceptorCMT.java:166)
at de.asdis.acm.interceptor.jboss.ApiExceptionInterceptor.invoke(ApiExceptionInterceptor.java:33)
at org.jboss.ejb.plugins.SecurityInterceptor.invoke(SecurityInterceptor.java:139)
at org.jboss.ejb.plugins.LogInterceptor.invoke(LogInterceptor.java:192)
at org.jboss.ejb.plugins.ProxyFactoryFinderInterceptor.invoke(ProxyFactoryFinderInterceptor.java:122)
at org.jboss.ejb.SessionContainer.internalInvoke(SessionContainer.java:624)
at org.jboss.ejb.Container.invoke(Container.java:873)
at sun.reflect.GeneratedMethodAccessor212.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:324)
at org.jboss.mx.interceptor.ReflectedDispatcher.invoke(ReflectedDispatcher.java:141)
at org.jboss.mx.server.Invocation.dispatch(Invocation.java:80)
at org.jboss.mx.server.Invocation.invoke(Invocation.java:72)
at org.jboss.mx.server.AbstractMBeanInvoker.invoke(AbstractMBeanInvoker.java:249)
at org.jboss.mx.server.MBeanServerImpl.invoke(MBeanServerImpl.java:644)
at org.jboss.invocation.jrmp.server.JRMPInvoker$MBeanServerAction.invoke(JRMPInvoker.java:805)
at org.jboss.invocation.jrmp.server.JRMPInvoker.invoke(JRMPInvoker.java:406)
at sun.reflect.GeneratedMethodAccessor211.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:324)
at sun.rmi.server.UnicastServerRef.dispatch(UnicastServerRef.java:261)
at sun.rmi.transport.Transport$1.run(Transport.java:148)
at java.security.AccessController.doPrivileged(Native Method)
at sun.rmi.transport.Transport.serviceCall(Transport.java:144)
at sun.rmi.transport.tcp.TCPTransport.handleMessages(TCPTransport.java:460)
at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run(TCPTransport.java:701)
at java.lang.Thread.run(Thread.java:534)