]
Gail Badner commented on HHH-2881:
----------------------------------
Please attach a runnable test case (Java + mapping).
PersistantBag.initializeFromCache can be intercepted by
CollectionLoadContext.getLoadingCollection and so corrupt the collection
--------------------------------------------------------------------------------------------------------------------------------
Key: HHH-2881
URL:
http://opensource.atlassian.com/projects/hibernate/browse/HHH-2881
Project: Hibernate3
Issue Type: Bug
Environment: Hibernate Entity Manager 3.3.1 GA, oracle,
Reporter: Pavol Zibrita
It can occur that while PersistenBag.initializeFromCache is called to populate the
collection from cache, the collection is populated also from
CollectionLoadContext.getLoadingCollection, and so, the collection is filled with more
data than needed. As the initializeFromCache uses direct access to the property this.bag,
it will continue loading the collection. Here is the stack trace of what happens:
PersistentBag.beforeInitialize(CollectionPersister, int) line: xx //here is the same
collection reinitialized again, and loaded again
CollectionLoadContext.getLoadingCollection(CollectionPersister, Serializable) line:
127
EntityLoader(Loader).readCollectionElement(Object, Serializable, CollectionPersister,
CollectionAliases, ResultSet, SessionImplementor) line: 1003
EntityLoader(Loader).readCollectionElements(Object[], ResultSet, SessionImplementor)
line: 646
EntityLoader(Loader).getRowFromResultSet(ResultSet, SessionImplementor,
QueryParameters, LockMode[], EntityKey, List, EntityKey[], boolean) line: 591
EntityLoader(Loader).doQuery(SessionImplementor, QueryParameters, boolean) line: 701
EntityLoader(Loader).doQueryAndInitializeNonLazyCollections(SessionImplementor,
QueryParameters, boolean) line: 236
EntityLoader(Loader).loadEntity(SessionImplementor, Object, Type, Object, String,
Serializable, EntityPersister) line: 1860
EntityLoader(AbstractEntityLoader).load(SessionImplementor, Object, Object,
Serializable) line: 48
EntityLoader(AbstractEntityLoader).load(Serializable, Object, SessionImplementor)
line: 42
SingleTableEntityPersister(AbstractEntityPersister).load(Serializable, Object,
LockMode, SessionImplementor) line: 3044
DefaultLoadEventListener.loadFromDatasource(LoadEvent, EntityPersister, EntityKey,
LoadEventListener$LoadType) line: 395
DefaultLoadEventListener.doLoad(LoadEvent, EntityPersister, EntityKey,
LoadEventListener$LoadType) line: 375
DefaultLoadEventListener.load(LoadEvent, EntityPersister, EntityKey,
LoadEventListener$LoadType) line: 139
DefaultLoadEventListener.proxyOrLoad(LoadEvent, EntityPersister, EntityKey,
LoadEventListener$LoadType) line: 195
DefaultLoadEventListener.onLoad(LoadEvent, LoadEventListener$LoadType) line: 103
SessionImpl.fireLoad(LoadEvent, LoadEventListener$LoadType) line: 878
SessionImpl.internalLoad(String, Serializable, boolean, boolean) line: 846
ManyToOneType(EntityType).resolveIdentifier(Serializable, SessionImplementor) line:
557
ManyToOneType.assemble(Serializable, SessionImplementor, Object) line: 196
TypeFactory.assemble(Serializable[], Type[], SessionImplementor, Object) line: 420
CacheEntry.assemble(Serializable[], Object, Serializable, EntityPersister,
Interceptor, EventSource) line: 96
CacheEntry.assemble(Object, Serializable, EntityPersister, Interceptor, EventSource)
line: 82
DefaultLoadEventListener.assembleCacheEntry(CacheEntry, Serializable, EntityPersister,
LoadEvent) line: 553
DefaultLoadEventListener.loadFromSecondLevelCache(LoadEvent, EntityPersister,
LoadEventListener$LoadType) line: 508
DefaultLoadEventListener.doLoad(LoadEvent, EntityPersister, EntityKey,
LoadEventListener$LoadType) line: 357
DefaultLoadEventListener.load(LoadEvent, EntityPersister, EntityKey,
LoadEventListener$LoadType) line: 139
DefaultLoadEventListener.proxyOrLoad(LoadEvent, EntityPersister, EntityKey,
LoadEventListener$LoadType) line: 195
DefaultLoadEventListener.onLoad(LoadEvent, LoadEventListener$LoadType) line: 103
SessionImpl.fireLoad(LoadEvent, LoadEventListener$LoadType) line: 878
SessionImpl.internalLoad(String, Serializable, boolean, boolean) line: 846
ManyToOneType(EntityType).resolveIdentifier(Serializable, SessionImplementor) line:
557
ManyToOneType.assemble(Serializable, SessionImplementor, Object) line: 196
PersistentBag.initializeFromCache(CollectionPersister, Serializable, Object) line: xxx
//NOW HERE IS THE Bag initializing from cache, it fails, see top of the stack!!
CollectionCacheEntry.assemble(PersistentCollection, CollectionPersister, Object) line:
35
DefaultInitializeCollectionEventListener.initializeCollectionFromCache(Serializable,
CollectionPersister, PersistentCollection, SessionImplementor) line: 130
DefaultInitializeCollectionEventListener.onInitializeCollection(InitializeCollectionEvent)
line: 48
SessionImpl.initializeCollection(PersistentCollection, boolean) line: 1716
PersistentBag(AbstractPersistentCollection).forceInitialization() line: 454
StatefulPersistenceContext.initializeNonLazyCollections() line: 794
QueryLoader(Loader).doQueryAndInitializeNonLazyCollections(SessionImplementor,
QueryParameters, boolean) line: 241
QueryLoader(Loader).doList(SessionImplementor, QueryParameters) line: 2220
QueryLoader(Loader).listIgnoreQueryCache(SessionImplementor, QueryParameters) line:
2104
QueryLoader(Loader).list(SessionImplementor, QueryParameters, Set, Type[]) line: 2099
QueryLoader.list(SessionImplementor, QueryParameters) line: 378
QueryTranslatorImpl.list(SessionImplementor, QueryParameters) line: 338
HQLQueryPlan.performList(QueryParameters, SessionImplementor) line: 172
SessionImpl.list(String, QueryParameters) line: 1121
QueryImpl.list() line: 79
QueryImpl.getResultList() line: 66
//some stack before, uninportant
Small fix to the PersistantBag has resolved this issue, however I cannot tell if it is
correct by some hibernate principles:
public void initializeFromCache(CollectionPersister persister, Serializable
disassembled, Object owner)
throws HibernateException {
Serializable[] array = (Serializable[]) disassembled;
int size = array.length;
List<Object> elements = new ArrayList<Object>(size);
for ( int i = 0; i < size; i++ ) {
Object element = persister.getElementType().assemble( array[i], getSession(), owner
);
if ( element!=null ) {
elements.add( element );
}
}
beforeInitialize( persister, size );
for ( Object element : elements ) {
this.bag.add( element );
}
}
Difference is, before the this.bag.add(element) was called in first cycle, where the line
of getting the element could cause reinitializing the collection and filling it up. There
are various possibilities how to fix the problem, but I don't know if the fix is at
the right place!
--
This message is automatically generated by JIRA.
-
If you think it was sent incorrectly contact one of the administrators: