HHH-17309 Introduce EntityHolder to unify proxy/entity management in single map

This commit is contained in:
Christian Beikov 2023-09-07 19:35:04 +02:00
parent f8596cd646
commit ed34a5d070
7 changed files with 222 additions and 84 deletions

View File

@ -172,8 +172,7 @@ public class EntityDeleteAction extends EntityAction {
} }
entry.postDelete(); entry.postDelete();
final EntityKey key = entry.getEntityKey(); final EntityKey key = entry.getEntityKey();
persistenceContext.removeEntity( key ); persistenceContext.removeEntityHolder( key );
persistenceContext.removeProxy( key );
removeCacheItem( ck ); removeCacheItem( ck );
persistenceContext.getNaturalIdResolutions().removeSharedResolution( id, naturalIdValues, persister ); persistenceContext.getNaturalIdResolutions().removeSharedResolution( id, naturalIdValues, persister );
postDelete(); postDelete();

View File

@ -20,7 +20,7 @@ import java.util.IdentityHashMap;
import java.util.Iterator; import java.util.Iterator;
import java.util.Map; import java.util.Map;
import java.util.Map.Entry; import java.util.Map.Entry;
import java.util.concurrent.ConcurrentMap; import java.util.NoSuchElementException;
import java.util.function.BiConsumer; import java.util.function.BiConsumer;
import java.util.function.Consumer; import java.util.function.Consumer;
import java.util.function.Supplier; import java.util.function.Supplier;
@ -41,6 +41,7 @@ import org.hibernate.engine.spi.BatchFetchQueue;
import org.hibernate.engine.spi.CollectionEntry; import org.hibernate.engine.spi.CollectionEntry;
import org.hibernate.engine.spi.CollectionKey; import org.hibernate.engine.spi.CollectionKey;
import org.hibernate.engine.spi.EntityEntry; import org.hibernate.engine.spi.EntityEntry;
import org.hibernate.engine.spi.EntityHolder;
import org.hibernate.engine.spi.EntityKey; import org.hibernate.engine.spi.EntityKey;
import org.hibernate.engine.spi.EntityUniqueKey; import org.hibernate.engine.spi.EntityUniqueKey;
import org.hibernate.engine.spi.NaturalIdResolutions; import org.hibernate.engine.spi.NaturalIdResolutions;
@ -53,7 +54,6 @@ import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.engine.spi.Status; import org.hibernate.engine.spi.Status;
import org.hibernate.internal.CoreMessageLogger; import org.hibernate.internal.CoreMessageLogger;
import org.hibernate.internal.util.collections.CollectionHelper; import org.hibernate.internal.util.collections.CollectionHelper;
import org.hibernate.internal.util.collections.ConcurrentReferenceHashMap;
import org.hibernate.internal.util.collections.IdentityMap; import org.hibernate.internal.util.collections.IdentityMap;
import org.hibernate.metamodel.spi.MappingMetamodelImplementor; import org.hibernate.metamodel.spi.MappingMetamodelImplementor;
import org.hibernate.persister.collection.CollectionPersister; import org.hibernate.persister.collection.CollectionPersister;
@ -106,13 +106,11 @@ public class StatefulPersistenceContext implements PersistenceContext {
*/ */
// Loaded entity instances, by EntityKey // Loaded entity instances, by EntityKey
private HashMap<EntityKey, Object> entitiesByKey; private HashMap<EntityKey, EntityHolderImpl> entitiesByKey;
// Loaded entity instances, by EntityUniqueKey // Loaded entity instances, by EntityUniqueKey
private HashMap<EntityUniqueKey, Object> entitiesByUniqueKey; private HashMap<EntityUniqueKey, Object> entitiesByUniqueKey;
// Entity proxies, by EntityKey
private ConcurrentReferenceHashMap<EntityKey, Object> proxiesByKey;
// Snapshots of current database state for entities // Snapshots of current database state for entities
// that have *not* been loaded // that have *not* been loaded
@ -169,18 +167,11 @@ public class StatefulPersistenceContext implements PersistenceContext {
this.entityEntryContext = new EntityEntryContext( this ); this.entityEntryContext = new EntityEntryContext( this );
} }
private ConcurrentMap<EntityKey, Object> getOrInitializeProxiesByKey() { private Map<EntityKey, EntityHolderImpl> getOrInitializeEntitiesByKey() {
if ( proxiesByKey == null ) { if ( entitiesByKey == null ) {
proxiesByKey = new ConcurrentReferenceHashMap<>( entitiesByKey = CollectionHelper.mapOfSize( INIT_COLL_SIZE );
INIT_COLL_SIZE,
.75f,
1,
ConcurrentReferenceHashMap.ReferenceType.STRONG,
ConcurrentReferenceHashMap.ReferenceType.WEAK,
null
);
} }
return proxiesByKey; return entitiesByKey;
} }
@Override @Override
@ -229,11 +220,11 @@ public class StatefulPersistenceContext implements PersistenceContext {
@Override @Override
public void clear() { public void clear() {
if ( proxiesByKey != null ) { if ( entitiesByKey != null ) {
//Strictly avoid lambdas in this case //Strictly avoid lambdas in this case
for ( Object value : proxiesByKey.values() ) { for ( EntityHolderImpl value : entitiesByKey.values() ) {
if ( value != null) { if ( value != null && value.proxy != null ) {
HibernateProxy.extractLazyInitializer( value ).unsetSession(); HibernateProxy.extractLazyInitializer( value.proxy ).unsetSession();
} }
} }
} }
@ -253,7 +244,6 @@ public class StatefulPersistenceContext implements PersistenceContext {
nonlazyCollections = null; nonlazyCollections = null;
collectionEntries = null; collectionEntries = null;
unownedCollections = null; unownedCollections = null;
proxiesByKey = null;
nullifiableEntityKeys = null; nullifiableEntityKeys = null;
deletedUnloadedEntityKeys = null; deletedUnloadedEntityKeys = null;
if ( batchFetchQueue != null ) { if ( batchFetchQueue != null ) {
@ -380,11 +370,21 @@ public class StatefulPersistenceContext implements PersistenceContext {
} }
@Override @Override
public void addEntity(EntityKey key, Object entity) { public EntityHolderImpl getEntityHolder(EntityKey key) {
if ( entitiesByKey == null ) { return entitiesByKey == null ? null : entitiesByKey.get( key );
entitiesByKey = CollectionHelper.mapOfSize( INIT_COLL_SIZE ); }
@Override
public boolean containsEntityHolder(EntityKey key) {
return entitiesByKey != null && entitiesByKey.get( key ) != null;
}
@Override
public void addEntity(EntityKey key, Object entity) {
final EntityHolderImpl holder = getOrInitializeEntitiesByKey().putIfAbsent( key, EntityHolderImpl.forEntity( entity ) );
if ( holder != null ) {
holder.entity = entity;
} }
entitiesByKey.put( key, entity );
final BatchFetchQueue fetchQueue = this.batchFetchQueue; final BatchFetchQueue fetchQueue = this.batchFetchQueue;
if ( fetchQueue != null ) { if ( fetchQueue != null ) {
fetchQueue.removeBatchLoadableEntityKey( key ); fetchQueue.removeBatchLoadableEntityKey( key );
@ -393,20 +393,36 @@ public class StatefulPersistenceContext implements PersistenceContext {
@Override @Override
public Object getEntity(EntityKey key) { public Object getEntity(EntityKey key) {
return entitiesByKey == null ? null : entitiesByKey.get( key ); final EntityHolderImpl holder = entitiesByKey == null ? null : entitiesByKey.get( key );
return holder == null ? null : holder.entity;
} }
@Override @Override
public boolean containsEntity(EntityKey key) { public boolean containsEntity(EntityKey key) {
return entitiesByKey != null && entitiesByKey.containsKey( key ); final EntityHolderImpl holder = entitiesByKey == null ? null : entitiesByKey.get( key );
return holder != null && holder.entity != null;
} }
@Override @Override
public Object removeEntity(EntityKey key) { public Object removeEntity(EntityKey key) {
final Object entity; final EntityHolderImpl holder = removeEntityHolder( key );
if ( holder != null ) {
final Object entity = holder.entity;
if ( holder.proxy != null ) {
entitiesByKey.put( key, holder );
}
return entity;
}
return null;
}
@Override
public EntityHolderImpl removeEntityHolder(EntityKey key) {
final EntityHolderImpl holder;
if ( entitiesByKey != null ) { if ( entitiesByKey != null ) {
entity = entitiesByKey.remove( key ); holder = entitiesByKey.remove( key );
if ( entitiesByUniqueKey != null ) { if ( entitiesByUniqueKey != null ) {
final Object entity = holder == null ? null : holder.entity;
final Iterator<?> itr = entitiesByUniqueKey.values().iterator(); final Iterator<?> itr = entitiesByUniqueKey.values().iterator();
while ( itr.hasNext() ) { while ( itr.hasNext() ) {
if ( itr.next() == entity ) { if ( itr.next() == entity ) {
@ -416,7 +432,7 @@ public class StatefulPersistenceContext implements PersistenceContext {
} }
} }
else { else {
entity = null; holder = null;
} }
// Clear all parent cache // Clear all parent cache
@ -432,7 +448,7 @@ public class StatefulPersistenceContext implements PersistenceContext {
fetchQueue.removeBatchLoadableEntityKey( key ); fetchQueue.removeBatchLoadableEntityKey( key );
fetchQueue.removeSubselect( key ); fetchQueue.removeSubselect( key );
} }
return entity; return holder;
} }
@Override @Override
@ -578,7 +594,14 @@ public class StatefulPersistenceContext implements PersistenceContext {
@Override @Override
public boolean containsProxy(Object entity) { public boolean containsProxy(Object entity) {
return proxiesByKey != null && proxiesByKey.containsValue( entity ); if ( entitiesByKey != null ) {
for ( EntityHolderImpl holder : entitiesByKey.values() ) {
if ( holder.proxy == entity ) {
return true;
}
}
}
return false;
} }
@Override @Override
@ -631,7 +654,13 @@ public class StatefulPersistenceContext implements PersistenceContext {
.getEntityDescriptor( li.getEntityName() ); .getEntityDescriptor( li.getEntityName() );
final EntityKey key = session.generateEntityKey( li.getInternalIdentifier(), persister ); final EntityKey key = session.generateEntityKey( li.getInternalIdentifier(), persister );
// any earlier proxy takes precedence // any earlier proxy takes precedence
getOrInitializeProxiesByKey().putIfAbsent( key, proxy ); final EntityHolderImpl holder = getOrInitializeEntitiesByKey().putIfAbsent(
key,
EntityHolderImpl.forProxy( proxy )
);
if ( holder != null && holder.proxy == null ) {
holder.proxy = proxy;
}
proxy.getHibernateLazyInitializer().setSession( session ); proxy.getHibernateLazyInitializer().setSession( session );
} }
} }
@ -733,8 +762,11 @@ public class StatefulPersistenceContext implements PersistenceContext {
} }
private Object removeProxyByKey(final EntityKey key) { private Object removeProxyByKey(final EntityKey key) {
if ( proxiesByKey != null ) { final EntityHolderImpl entityHolder;
return proxiesByKey.remove( key ); if ( entitiesByKey != null && ( entityHolder = entitiesByKey.get( key ) ) != null ) {
Object proxy = entityHolder.proxy;
entityHolder.proxy = null;
return proxy;
} }
return null; return null;
} }
@ -759,10 +791,10 @@ public class StatefulPersistenceContext implements PersistenceContext {
@Override @Override
public void addEnhancedProxy(EntityKey key, PersistentAttributeInterceptable entity) { public void addEnhancedProxy(EntityKey key, PersistentAttributeInterceptable entity) {
if ( entitiesByKey == null ) { final EntityHolderImpl holder = getOrInitializeEntitiesByKey().putIfAbsent( key, EntityHolderImpl.forEntity( entity ) );
entitiesByKey = CollectionHelper.mapOfSize( INIT_COLL_SIZE ); if ( holder != null ) {
holder.entity = entity;
} }
entitiesByKey.put( key, entity );
} }
@Override @Override
@ -1044,12 +1076,16 @@ public class StatefulPersistenceContext implements PersistenceContext {
@Override @Override
public Object getProxy(EntityKey key) { public Object getProxy(EntityKey key) {
return proxiesByKey == null ? null : proxiesByKey.get( key ); final EntityHolderImpl holder = entitiesByKey == null ? null : entitiesByKey.get( key );
return holder == null ? null : holder.proxy;
} }
@Override @Override
public void addProxy(EntityKey key, Object proxy) { public void addProxy(EntityKey key, Object proxy) {
getOrInitializeProxiesByKey().put( key, proxy ); final EntityHolderImpl holder = getOrInitializeEntitiesByKey().putIfAbsent( key, EntityHolderImpl.forProxy( proxy ) );
if ( holder != null ) {
holder.proxy = proxy;
}
} }
@Override @Override
@ -1077,12 +1113,60 @@ public class StatefulPersistenceContext implements PersistenceContext {
@Deprecated @Deprecated
@Override @Override
public Map<EntityKey,Object> getEntitiesByKey() { public Map<EntityKey,Object> getEntitiesByKey() {
return entitiesByKey == null ? Collections.emptyMap() : entitiesByKey; if ( entitiesByKey == null ) {
return Collections.emptyMap();
}
final HashMap<EntityKey, Object> result = CollectionHelper.mapOfSize( entitiesByKey.size() );
for ( Entry<EntityKey, EntityHolderImpl> entry : entitiesByKey.entrySet() ) {
if ( entry.getValue().entity != null ) {
result.put( entry.getKey(), entry.getValue().entity );
}
}
return result;
}
@Override
public Map<EntityKey, EntityHolder> getEntityHoldersByKey() {
//noinspection unchecked,rawtypes
return (Map) entitiesByKey;
} }
@Override @Override
public Iterator<Object> managedEntitiesIterator() { public Iterator<Object> managedEntitiesIterator() {
return entitiesByKey == null ? Collections.emptyIterator() : entitiesByKey.values().iterator(); if ( entitiesByKey == null ) {
return Collections.emptyIterator();
}
final Iterator<EntityHolderImpl> iterator = entitiesByKey.values().iterator();
final var iter = new Iterator<Object>() {
Object next;
void prepareNext() {
next = null;
while ( iterator.hasNext() ) {
final EntityHolderImpl next = iterator.next();
if ( next.entity != null ) {
this.next = next.entity;
break;
}
}
}
@Override
public boolean hasNext() {
return next != null;
}
@Override
public Object next() {
final Object next = this.next;
if ( next == null ) {
throw new NoSuchElementException();
}
prepareNext();
return next;
}
};
iter.prepareNext();
return iter;
} }
@Override @Override
@ -1525,7 +1609,8 @@ public class StatefulPersistenceContext implements PersistenceContext {
@Override @Override
public void replaceDelayedEntityIdentityInsertKeys(EntityKey oldKey, Object generatedId) { public void replaceDelayedEntityIdentityInsertKeys(EntityKey oldKey, Object generatedId) {
final Object entity = entitiesByKey == null ? null : entitiesByKey.remove( oldKey ); final EntityHolderImpl holder = entitiesByKey == null ? null : entitiesByKey.remove( oldKey );
final Object entity = holder == null ? null : holder.entity;
final EntityEntry oldEntry = entityEntryContext.removeEntityEntry( entity ); final EntityEntry oldEntry = entityEntryContext.removeEntityEntry( entity );
this.parentsByChild = null; this.parentsByChild = null;
@ -1558,21 +1643,20 @@ public class StatefulPersistenceContext implements PersistenceContext {
oos.writeBoolean( defaultReadOnly ); oos.writeBoolean( defaultReadOnly );
oos.writeBoolean( hasNonReadOnlyEntities ); oos.writeBoolean( hasNonReadOnlyEntities );
final Serializer<Entry<EntityKey, Object>> entityKeySerializer = (entry, stream) -> { writeMapToStream( entitiesByKey, oos, "entitiesByKey", (entry, stream) -> {
entry.getKey().serialize( stream );
final EntityHolderImpl holder = entry.getValue();
stream.writeObject( holder.entity );
stream.writeObject( holder.proxy );
} );
writeMapToStream( entitiesByUniqueKey, oos, "entitiesByUniqueKey", (entry, stream) -> {
entry.getKey().serialize( stream ); entry.getKey().serialize( stream );
stream.writeObject( entry.getValue() ); stream.writeObject( entry.getValue() );
}; } );
writeMapToStream( entitySnapshotsByKey, oos, "entitySnapshotsByKey", (entry, stream) -> {
writeMapToStream( entitiesByKey, oos, "entitiesByKey", entityKeySerializer );
writeMapToStream(
entitiesByUniqueKey,
oos, "entitiesByUniqueKey", (entry, stream) -> {
entry.getKey().serialize( stream ); entry.getKey().serialize( stream );
stream.writeObject( entry.getValue() ); stream.writeObject( entry.getValue() );
} } );
);
writeMapToStream( proxiesByKey, oos, "proxiesByKey", entityKeySerializer );
writeMapToStream( entitySnapshotsByKey, oos, "entitySnapshotsByKey", entityKeySerializer );
entityEntryContext.serialize( oos ); entityEntryContext.serialize( oos );
writeMapToStream( writeMapToStream(
@ -1678,7 +1762,24 @@ public class StatefulPersistenceContext implements PersistenceContext {
} }
rtn.entitiesByKey = CollectionHelper.mapOfSize(Math.max(count, INIT_COLL_SIZE)); rtn.entitiesByKey = CollectionHelper.mapOfSize(Math.max(count, INIT_COLL_SIZE));
for ( int i = 0; i < count; i++ ) { for ( int i = 0; i < count; i++ ) {
rtn.entitiesByKey.put( EntityKey.deserialize( ois, sfi ), ois.readObject() ); final EntityKey ek = EntityKey.deserialize( ois, sfi );
final Object entity = ois.readObject();
final Object proxy = ois.readObject();
final EntityHolderImpl holder = EntityHolderImpl.forEntity( entity );
if ( proxy != null ) {
final LazyInitializer lazyInitializer = HibernateProxy.extractLazyInitializer( proxy );
if ( lazyInitializer != null ) {
lazyInitializer.setSession( session );
holder.proxy = proxy;
}
else {
// otherwise, the proxy was pruned during the serialization process
if ( traceEnabled ) {
LOG.trace( "Encountered pruned proxy" );
}
}
}
rtn.entitiesByKey.put( ek, holder );
} }
count = ois.readInt(); count = ois.readInt();
@ -1692,26 +1793,6 @@ public class StatefulPersistenceContext implements PersistenceContext {
} }
} }
count = ois.readInt();
if ( traceEnabled ) {
LOG.trace( "Starting deserialization of [" + count + "] proxiesByKey entries" );
}
for ( int i = 0; i < count; i++ ) {
final EntityKey ek = EntityKey.deserialize( ois, sfi );
final Object proxy = ois.readObject();
final LazyInitializer lazyInitializer = HibernateProxy.extractLazyInitializer( proxy );
if ( lazyInitializer != null ) {
lazyInitializer.setSession( session );
rtn.getOrInitializeProxiesByKey().put( ek, proxy );
}
else {
// otherwise, the proxy was pruned during the serialization process
if ( traceEnabled ) {
LOG.trace( "Encountered pruned proxy" );
}
}
}
count = ois.readInt(); count = ois.readInt();
if ( traceEnabled ) { if ( traceEnabled ) {
LOG.trace( "Starting deserialization of [" + count + "] entitySnapshotsByKey entries" ); LOG.trace( "Starting deserialization of [" + count + "] entitySnapshotsByKey entries" );
@ -1920,6 +2001,34 @@ public class StatefulPersistenceContext implements PersistenceContext {
} }
} }
private static class EntityHolderImpl implements EntityHolder, Serializable {
Object entity;
Object proxy;
private EntityHolderImpl(Object entity, Object proxy) {
this.entity = entity;
this.proxy = proxy;
}
@Override
public Object getEntity() {
return entity;
}
@Override
public Object getProxy() {
return proxy;
}
public static EntityHolderImpl forProxy(Object proxy) {
return new EntityHolderImpl( null, proxy );
}
public static EntityHolderImpl forEntity(Object entity) {
return new EntityHolderImpl( entity, null );
}
}
// NATURAL ID RESOLUTION HANDLING ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // NATURAL ID RESOLUTION HANDLING ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
private NaturalIdResolutionsImpl naturalIdResolutions; private NaturalIdResolutionsImpl naturalIdResolutions;

View File

@ -0,0 +1,12 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
*/
package org.hibernate.engine.spi;
public interface EntityHolder {
Object getEntity();
Object getProxy();
}

View File

@ -482,12 +482,24 @@ public interface PersistenceContext {
// @Deprecated // @Deprecated
// HashSet getNullifiableEntityKeys(); // HashSet getNullifiableEntityKeys();
EntityHolder getEntityHolder(EntityKey key);
boolean containsEntityHolder(EntityKey key);
EntityHolder removeEntityHolder(EntityKey key);
/** /**
* Doubly internal * Doubly internal
*/ */
@Internal @Internal
Map<EntityKey,Object> getEntitiesByKey(); Map<EntityKey,Object> getEntitiesByKey();
/**
* Doubly internal
*/
@Internal
Map<EntityKey,EntityHolder> getEntityHoldersByKey();
/** /**
* Provides access to the entity/EntityEntry combos associated with the persistence context in a manner that * Provides access to the entity/EntityEntry combos associated with the persistence context in a manner that
* is safe from reentrant access. Specifically, it is safe from additions/removals while iterating. * is safe from reentrant access. Specifically, it is safe from additions/removals while iterating.

View File

@ -122,7 +122,7 @@ public abstract class AbstractFlushingEventListener implements JpaBootstrapSensi
persistenceContext.getCollectionEntriesSize() persistenceContext.getCollectionEntriesSize()
); );
new EntityPrinter( session.getFactory() ).toString( new EntityPrinter( session.getFactory() ).toString(
persistenceContext.getEntitiesByKey().entrySet() persistenceContext.getEntityHoldersByKey().entrySet()
); );
} }

View File

@ -11,6 +11,7 @@ import org.hibernate.engine.internal.Cascade;
import org.hibernate.engine.internal.CascadePoint; import org.hibernate.engine.internal.CascadePoint;
import org.hibernate.engine.spi.CascadingActions; import org.hibernate.engine.spi.CascadingActions;
import org.hibernate.engine.spi.EntityEntry; import org.hibernate.engine.spi.EntityEntry;
import org.hibernate.engine.spi.EntityHolder;
import org.hibernate.engine.spi.EntityKey; import org.hibernate.engine.spi.EntityKey;
import org.hibernate.engine.spi.PersistenceContext; import org.hibernate.engine.spi.PersistenceContext;
import org.hibernate.event.spi.EventSource; import org.hibernate.event.spi.EventSource;
@ -57,9 +58,9 @@ public class DefaultEvictEventListener implements EvictEventListener {
.getMappingMetamodel() .getMappingMetamodel()
.getEntityDescriptor( lazyInitializer.getEntityName() ); .getEntityDescriptor( lazyInitializer.getEntityName() );
final EntityKey key = source.generateEntityKey( id, persister ); final EntityKey key = source.generateEntityKey( id, persister );
persistenceContext.removeProxy( key ); final EntityHolder holder = persistenceContext.removeEntityHolder( key );
if ( !lazyInitializer.isUninitialized() ) { if ( !lazyInitializer.isUninitialized() ) {
final Object entity = persistenceContext.removeEntity( key ); final Object entity = holder.getEntity();
if ( entity != null ) { if ( entity != null ) {
EntityEntry entry = persistenceContext.removeEntry( entity ); EntityEntry entry = persistenceContext.removeEntry( entity );
doEvict( entity, key, entry.getPersister(), event.getSession() ); doEvict( entity, key, entry.getPersister(), event.getSession() );

View File

@ -12,6 +12,7 @@ import java.util.Map;
import org.hibernate.Hibernate; import org.hibernate.Hibernate;
import org.hibernate.HibernateException; import org.hibernate.HibernateException;
import org.hibernate.bytecode.enhance.spi.LazyPropertyInitializer; import org.hibernate.bytecode.enhance.spi.LazyPropertyInitializer;
import org.hibernate.engine.spi.EntityHolder;
import org.hibernate.engine.spi.EntityKey; import org.hibernate.engine.spi.EntityKey;
import org.hibernate.engine.spi.SessionFactoryImplementor; import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.engine.spi.TypedValue; import org.hibernate.engine.spi.TypedValue;
@ -103,19 +104,23 @@ public final class EntityPrinter {
} }
// Cannot use Map as an argument because it clashes with the previous method (due to type erasure) // Cannot use Map as an argument because it clashes with the previous method (due to type erasure)
public void toString(Iterable<Map.Entry<EntityKey, Object>> entitiesByEntityKey) throws HibernateException { public void toString(Iterable<Map.Entry<EntityKey, EntityHolder>> entitiesByEntityKey) throws HibernateException {
if ( !LOG.isDebugEnabled() || !entitiesByEntityKey.iterator().hasNext() ) { if ( !LOG.isDebugEnabled() || !entitiesByEntityKey.iterator().hasNext() ) {
return; return;
} }
LOG.debug( "Listing entities:" ); LOG.debug( "Listing entities:" );
int i = 0; int i = 0;
for ( Map.Entry<EntityKey, Object> entityKeyAndEntity : entitiesByEntityKey ) { for ( Map.Entry<EntityKey, EntityHolder> entityKeyAndEntity : entitiesByEntityKey ) {
final EntityHolder holder = entityKeyAndEntity.getValue();
if ( holder.getEntity() == null ) {
continue;
}
if ( i++ > 20 ) { if ( i++ > 20 ) {
LOG.debug( "More......" ); LOG.debug( "More......" );
break; break;
} }
LOG.debug( toString( entityKeyAndEntity.getKey().getEntityName(), entityKeyAndEntity.getValue() ) ); LOG.debug( toString( entityKeyAndEntity.getKey().getEntityName(), holder.getEntity() ) );
} }
} }