1414import org .hibernate .engine .spi .PersistentAttributeInterceptor ;
1515import org .hibernate .internal .CoreLogging ;
1616import org .hibernate .internal .CoreMessageLogger ;
17+ import org .hibernate .internal .util .collections .InstanceIdentityStore ;
18+ import org .hibernate .persister .entity .EntityPersister ;
1719
1820import java .io .IOException ;
1921import java .io .ObjectInputStream ;
@@ -49,7 +51,8 @@ public class EntityEntryContext {
4951
5052 private final transient PersistenceContext persistenceContext ;
5153
52- private transient IdentityHashMap <ManagedEntity ,ImmutableManagedEntityHolder > immutableManagedEntityXref ;
54+ private transient InstanceIdentityStore <ImmutableManagedEntityHolder > immutableManagedEntityXref ;
55+ private transient int currentInstanceId ;
5356
5457 private transient ManagedEntity head ;
5558 private transient ManagedEntity tail ;
@@ -107,21 +110,20 @@ public void addEntityEntry(Object entity, EntityEntry entityEntry) {
107110 else {
108111 // Create a holder for PersistenceContext-related data.
109112 managedEntity = new ImmutableManagedEntityHolder ( managed );
110- if ( immutableManagedEntityXref == null ) {
111- immutableManagedEntityXref = new IdentityHashMap <>();
113+ if ( !isReferenceCachingEnabled ( entityEntry .getPersister () ) ) {
114+ final int instanceId = nextManagedEntityInstanceId ();
115+ managed .$$_hibernate_setInstanceId ( instanceId );
116+ putImmutableManagedEntity ( managed , instanceId , (ImmutableManagedEntityHolder ) managedEntity );
117+ }
118+ else {
119+ // When reference caching is enabled we cannot set the instance-id on the entity instance
120+ putManagedEntity ( entity , managedEntity );
112121 }
113- immutableManagedEntityXref .put (
114- managed ,
115- (ImmutableManagedEntityHolder ) managedEntity
116- );
117122 }
118123 }
119124 else {
120- if ( nonEnhancedEntityXref == null ) {
121- nonEnhancedEntityXref = new IdentityHashMap <>();
122- }
123125 managedEntity = new ManagedEntityImpl ( entity );
124- nonEnhancedEntityXref . put ( entity , managedEntity );
126+ putManagedEntity ( entity , managedEntity );
125127 }
126128 }
127129
@@ -155,6 +157,12 @@ public void addEntityEntry(Object entity, EntityEntry entityEntry) {
155157 }
156158 }
157159
160+ private static boolean isReferenceCachingEnabled (EntityPersister persister ) {
161+ // Immutable entities which can use reference caching are treated as non-enhanced entities, as setting
162+ // the instance-id on them would be problematic in different sessions
163+ return persister .canUseReferenceCacheEntries () && persister .canReadFromCache ();
164+ }
165+
158166 private ManagedEntity getAssociatedManagedEntity (Object entity ) {
159167 if ( isManagedEntity ( entity ) ) {
160168 final ManagedEntity managedEntity = asManagedEntity ( entity );
@@ -170,20 +178,35 @@ private ManagedEntity getAssociatedManagedEntity(Object entity) {
170178 ? managedEntity // it is associated
171179 : null ;
172180 }
173- else {
174- // if managedEntity is associated with this EntityEntryContext, then
175- // it will have an entry in immutableManagedEntityXref and its
176- // holder will be returned.
181+ else if ( !isReferenceCachingEnabled ( entityEntry .getPersister () ) ) {
182+ // if managedEntity is associated with this EntityEntryContext, it may have
183+ // an entry in immutableManagedEntityXref and its holder will be returned.
177184 return immutableManagedEntityXref != null
178- ? immutableManagedEntityXref .get ( managedEntity )
185+ ? immutableManagedEntityXref .get ( managedEntity . $$_hibernate_getInstanceId (), managedEntity )
179186 : null ;
180187 }
181188 }
182- else {
183- return nonEnhancedEntityXref != null
184- ? nonEnhancedEntityXref .get ( entity )
185- : null ;
189+ return nonEnhancedEntityXref != null
190+ ? nonEnhancedEntityXref .get ( entity )
191+ : null ;
192+ }
193+
194+ private void putManagedEntity (Object entity , ManagedEntity managedEntity ) {
195+ if ( nonEnhancedEntityXref == null ) {
196+ nonEnhancedEntityXref = new IdentityHashMap <>();
186197 }
198+ nonEnhancedEntityXref .put ( entity , managedEntity );
199+ }
200+
201+ private int nextManagedEntityInstanceId () {
202+ return currentInstanceId ++;
203+ }
204+
205+ private void putImmutableManagedEntity (ManagedEntity managed , int instanceId , ImmutableManagedEntityHolder holder ) {
206+ if ( immutableManagedEntityXref == null ) {
207+ immutableManagedEntityXref = new InstanceIdentityStore <>();
208+ }
209+ immutableManagedEntityXref .put ( instanceId , managed , holder );
187210 }
188211
189212 private void checkNotAssociatedWithOtherPersistenceContextIfMutable (ManagedEntity managedEntity ) {
@@ -253,12 +276,16 @@ public EntityEntry removeEntityEntry(Object entity) {
253276
254277 dirty = true ;
255278
256- if (managedEntity instanceof ImmutableManagedEntityHolder ) {
257- assert entity == ( (ImmutableManagedEntityHolder ) managedEntity ).managedEntity ;
258- immutableManagedEntityXref .remove ( entity );
259-
279+ if ( managedEntity instanceof ImmutableManagedEntityHolder holder ) {
280+ assert entity == holder .managedEntity ;
281+ if ( !isReferenceCachingEnabled ( holder .$$_hibernate_getEntityEntry ().getPersister () ) ) {
282+ immutableManagedEntityXref .remove ( managedEntity .$$_hibernate_getInstanceId (), entity );
283+ }
284+ else {
285+ nonEnhancedEntityXref .remove ( entity );
286+ }
260287 }
261- else if ( ! ( isManagedEntity ( entity ) ) ) {
288+ else if ( !isManagedEntity ( entity ) ) {
262289 nonEnhancedEntityXref .remove ( entity );
263290 }
264291
@@ -387,6 +414,7 @@ public void clear() {
387414 count = 0 ;
388415
389416 reentrantSafeEntries = null ;
417+ currentInstanceId = 0 ;
390418 }
391419
392420 private static void clearManagedEntity (final ManagedEntity node ) {
@@ -478,30 +506,27 @@ public static EntityEntryContext deserialize(ObjectInputStream ois, StatefulPers
478506
479507 final ManagedEntity managedEntity ;
480508 if ( isEnhanced ) {
509+ final ManagedEntity castedEntity = asManagedEntity ( entity );
481510 if ( entry .getPersister ().isMutable () ) {
482- managedEntity = ManagedTypeHelper . asManagedEntity ( entity ) ;
511+ managedEntity = castedEntity ;
483512 }
484513 else {
485- final ManagedEntity castedEntity = asManagedEntity ( entity );
486514 managedEntity = new ImmutableManagedEntityHolder ( castedEntity );
487- if ( context .immutableManagedEntityXref == null ) {
488- context .immutableManagedEntityXref =
489- new IdentityHashMap <>();
515+ if ( !isReferenceCachingEnabled ( entry .getPersister () ) ) {
516+ final int instanceId = context .nextManagedEntityInstanceId ();
517+ castedEntity .$$_hibernate_setInstanceId ( instanceId );
518+ context .putImmutableManagedEntity ( castedEntity , instanceId , (ImmutableManagedEntityHolder ) managedEntity );
519+ }
520+ else {
521+ context .putManagedEntity ( entity , castedEntity );
490522 }
491- context .immutableManagedEntityXref .put (
492- castedEntity ,
493- (ImmutableManagedEntityHolder ) managedEntity
494-
495- );
496523 }
497524 }
498525 else {
499526 managedEntity = new ManagedEntityImpl ( entity );
500- if ( context .nonEnhancedEntityXref == null ) {
501- context .nonEnhancedEntityXref = new IdentityHashMap <>();
502- }
503- context .nonEnhancedEntityXref .put ( entity , managedEntity );
527+ context .putManagedEntity ( entity , managedEntity );
504528 }
529+
505530 managedEntity .$$_hibernate_setEntityEntry ( entry );
506531
507532 if ( previous == null ) {
@@ -605,6 +630,15 @@ public ManagedEntityImpl(Object entityInstance) {
605630 public void $$_hibernate_setPreviousManagedEntity (ManagedEntity previous ) {
606631 this .previous = previous ;
607632 }
633+
634+ @ Override
635+ public int $$_hibernate_getInstanceId () {
636+ return -1 ;
637+ }
638+
639+ @ Override
640+ public void $$_hibernate_setInstanceId (int id ) {
641+ }
608642 }
609643
610644 private static class ImmutableManagedEntityHolder implements ManagedEntity {
@@ -693,6 +727,16 @@ private boolean canClearEntityEntryReference() {
693727 return !(entityEntry instanceof ImmutableEntityEntry )
694728 || !entityEntry .getPersister ().canUseReferenceCacheEntries ();
695729 }
730+
731+ @ Override
732+ public int $$_hibernate_getInstanceId () {
733+ return managedEntity .$$_hibernate_getInstanceId ();
734+ }
735+
736+ @ Override
737+ public void $$_hibernate_setInstanceId (int id ) {
738+ managedEntity .$$_hibernate_setInstanceId ( id );
739+ }
696740 }
697741
698742 /**
0 commit comments