Skip to content

Commit

Permalink
HHH-18689 Maintain proxy targets when converting cache entries
Browse files Browse the repository at this point in the history
  • Loading branch information
beikov committed Oct 28, 2024
1 parent 76d7bfb commit 70332f1
Show file tree
Hide file tree
Showing 2 changed files with 73 additions and 48 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,16 @@
package org.hibernate.engine.internal;

import org.hibernate.LockMode;
import org.hibernate.engine.spi.EntityEntry;
import org.hibernate.engine.spi.EntityHolder;
import org.hibernate.engine.spi.EntityKey;
import org.hibernate.engine.spi.PersistenceContext;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.engine.spi.Status;
import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.proxy.LazyInitializer;

import static org.hibernate.proxy.HibernateProxy.extractLazyInitializer;

/**
* Functionality relating to the Hibernate two-phase loading process, that may be reused by persisters
Expand Down Expand Up @@ -39,16 +45,27 @@ public static void addUninitializedCachedEntity(
final LockMode lockMode,
final Object version,
final SharedSessionContractImplementor session) {
session.getPersistenceContextInternal().addEntity(
final PersistenceContext persistenceContext = session.getPersistenceContextInternal();
final EntityHolder entityHolder = persistenceContext.addEntityHolder( key, object );
final EntityEntry entityEntry = persistenceContext.addEntry(
object,
Status.LOADING,
null,
key,
null,
key.getIdentifier(),
version,
lockMode,
true,
persister,
false
);
entityHolder.setEntityEntry( entityEntry );
final Object proxy = entityHolder.getProxy();
if ( proxy != null ) {
// there is already a proxy for this impl
final LazyInitializer lazyInitializer = extractLazyInitializer( proxy );
assert lazyInitializer != null;
lazyInitializer.setImplementation( object );
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@
import org.hibernate.internal.CoreMessageLogger;
import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.pretty.MessageHelper;
import org.hibernate.proxy.HibernateProxy;
import org.hibernate.proxy.LazyInitializer;
import org.hibernate.sql.results.LoadingLogger;
import org.hibernate.stat.internal.StatsHelper;
import org.hibernate.stat.spi.StatisticsImplementor;
Expand All @@ -46,7 +46,8 @@
import static org.hibernate.engine.internal.ManagedTypeHelper.isManagedEntity;
import static org.hibernate.engine.internal.ManagedTypeHelper.isPersistentAttributeInterceptable;
import static org.hibernate.engine.internal.Versioning.getVersion;
import static org.hibernate.loader.ast.internal.LoaderHelper.upgradeLock;
import static org.hibernate.loader.ast.internal.LoaderHelper.upgradeLock;;
import static org.hibernate.proxy.HibernateProxy.extractLazyInitializer;

/**
* @author Vlad Mihalcea
Expand Down Expand Up @@ -388,7 +389,6 @@ private Object convertCacheEntryToEntity(
EntityKey entityKey) {

final SessionFactoryImplementor factory = source.getFactory();
final EntityPersister subclassPersister;

if ( LOG.isTraceEnabled() ) {
LOG.tracef(
Expand All @@ -398,19 +398,20 @@ private Object convertCacheEntryToEntity(
);
}

final Object entity;
final EntityPersister subclassPersister =
factory.getRuntimeMetamodels().getMappingMetamodel()
.getEntityDescriptor( entry.getSubclass() );
final PersistenceContext persistenceContext = source.getPersistenceContextInternal();
final EntityHolder oldHolder = persistenceContext.getEntityHolder( entityKey );

subclassPersister = factory.getRuntimeMetamodels()
.getMappingMetamodel()
.getEntityDescriptor( entry.getSubclass() );
final Object entity;
if ( instanceToLoad != null ) {
entity = instanceToLoad;
}
else {
final EntityHolder holder = source.getPersistenceContextInternal().getEntityHolder( entityKey );
if ( holder != null && holder.getEntity() != null ) {
if ( oldHolder != null && oldHolder.getEntity() != null ) {
// Use the entity which might already be
entity = holder.getEntity();
entity = oldHolder.getEntity();
}
else {
entity = source.instantiate( subclassPersister, entityId );
Expand All @@ -430,23 +431,39 @@ private Object convertCacheEntryToEntity(
}

// make it circular-reference safe
TwoPhaseLoad.addUninitializedCachedEntity(
entityKey,
entity,
subclassPersister,
LockMode.NONE,
entry.getVersion(),
source
);

final PersistenceContext persistenceContext = source.getPersistenceContext();
final Object[] values;
final Object version;
final EntityHolder holder = persistenceContext.addEntityHolder( entityKey, entity );
final Object proxy = holder.getProxy();
final boolean isReadOnly;
if ( proxy != null ) {
// there is already a proxy for this impl
// only set the status to read-only if the proxy is read-only
final LazyInitializer lazyInitializer = extractLazyInitializer( proxy );
assert lazyInitializer != null;
lazyInitializer.setImplementation( entity );

isReadOnly = lazyInitializer.isReadOnly();
}
else {
isReadOnly = source.isDefaultReadOnly();
}
holder.setEntityEntry(
persistenceContext.addEntry(
entity,
Status.LOADING,
null,
null,
entityKey.getIdentifier(),
entry.getVersion(),
LockMode.NONE,
true,
persister,
false
)
);

final Type[] types = subclassPersister.getPropertyTypes();
// initializes the entity by (desired) side-effect
values = ( (StandardCacheEntryImpl) entry ).assemble(
final Object[] values = ( (StandardCacheEntryImpl) entry ).assemble(
entity,
entityId,
subclassPersister,
Expand All @@ -462,32 +479,23 @@ private Object convertCacheEntryToEntity(
source
);
}
version = getVersion( values, subclassPersister );
final Object version = getVersion( values, subclassPersister );
LOG.tracef( "Cached Version : %s", version );

final Object proxy = persistenceContext.getProxy( entityKey );
if ( proxy != null ) {
// there is already a proxy for this impl
// only set the status to read-only if the proxy is read-only
isReadOnly = HibernateProxy.extractLazyInitializer( proxy ).isReadOnly();
}
else {
isReadOnly = source.isDefaultReadOnly();
}

EntityEntry entityEntry = persistenceContext.addEntry(
entity,
( isReadOnly ? Status.READ_ONLY : Status.MANAGED ),
values,
null,
entityId,
version,
LockMode.NONE,
true,
subclassPersister,
false
holder.setEntityEntry(
persistenceContext.addEntry(
entity,
isReadOnly ? Status.READ_ONLY : Status.MANAGED,
values,
null,
entityId,
version,
LockMode.NONE,
true,
subclassPersister,
false
)
);
persistenceContext.getEntityHolder( entityKey ).setEntityEntry( entityEntry );
subclassPersister.afterInitialize( entity, source );
persistenceContext.initializeNonLazyCollections();

Expand Down

0 comments on commit 70332f1

Please sign in to comment.