diff --git a/hibernate-core/src/main/java/org/hibernate/engine/internal/AbstractTransactionCompletionProcessQueue.java b/hibernate-core/src/main/java/org/hibernate/engine/internal/AbstractTransactionCompletionProcessQueue.java index 6ee772b9d4a7..a5b706b9c107 100644 --- a/hibernate-core/src/main/java/org/hibernate/engine/internal/AbstractTransactionCompletionProcessQueue.java +++ b/hibernate-core/src/main/java/org/hibernate/engine/internal/AbstractTransactionCompletionProcessQueue.java @@ -16,23 +16,23 @@ * * @author Steve Ebersole */ -public abstract class AbstractTransactionCompletionProcessQueue { - protected SharedSessionContractImplementor session; +abstract class AbstractTransactionCompletionProcessQueue { + SharedSessionContractImplementor session; // Concurrency handling required when transaction completion process is dynamically registered // inside event listener (HHH-7478). - protected ConcurrentLinkedQueue<@NonNull T> processes = new ConcurrentLinkedQueue<>(); + ConcurrentLinkedQueue<@NonNull T> processes = new ConcurrentLinkedQueue<>(); - protected AbstractTransactionCompletionProcessQueue(SharedSessionContractImplementor session) { + AbstractTransactionCompletionProcessQueue(SharedSessionContractImplementor session) { this.session = session; } - public void register(@Nullable T process) { + void register(@Nullable T process) { if ( process != null ) { processes.add( process ); } } - public boolean hasActions() { + boolean hasActions() { return !processes.isEmpty(); } } diff --git a/hibernate-core/src/main/java/org/hibernate/engine/internal/AfterTransactionCompletionProcessQueue.java b/hibernate-core/src/main/java/org/hibernate/engine/internal/AfterTransactionCompletionProcessQueue.java index b910e3ee8ad9..ddcd55f70d84 100644 --- a/hibernate-core/src/main/java/org/hibernate/engine/internal/AfterTransactionCompletionProcessQueue.java +++ b/hibernate-core/src/main/java/org/hibernate/engine/internal/AfterTransactionCompletionProcessQueue.java @@ -19,25 +19,25 @@ /** * Encapsulates behavior needed for after transaction processing */ -public class AfterTransactionCompletionProcessQueue +class AfterTransactionCompletionProcessQueue extends AbstractTransactionCompletionProcessQueue { private final Set querySpacesToInvalidate = new HashSet<>(); - public AfterTransactionCompletionProcessQueue(SharedSessionContractImplementor session) { + AfterTransactionCompletionProcessQueue(SharedSessionContractImplementor session) { super( session ); } - public void addSpaceToInvalidate(String space) { + void addSpaceToInvalidate(String space) { querySpacesToInvalidate.add( space ); } @Override - public boolean hasActions() { + boolean hasActions() { return super.hasActions() || !querySpacesToInvalidate.isEmpty(); } - public void afterTransactionCompletion(boolean success) { + void afterTransactionCompletion(boolean success) { AfterCompletionCallback process; while ( (process = processes.poll()) != null ) { try { @@ -61,7 +61,7 @@ public void afterTransactionCompletion(boolean success) { querySpacesToInvalidate.clear(); } - public void executePendingBulkOperationCleanUpActions() { + void executePendingBulkOperationCleanUpActions() { AfterCompletionCallback process; boolean hasPendingBulkOperationCleanUpActions = false; while ( ( process = processes.poll() ) != null ) { diff --git a/hibernate-core/src/main/java/org/hibernate/engine/internal/BeforeTransactionCompletionProcessQueue.java b/hibernate-core/src/main/java/org/hibernate/engine/internal/BeforeTransactionCompletionProcessQueue.java index ae6f81e63d18..fb40c87c4916 100644 --- a/hibernate-core/src/main/java/org/hibernate/engine/internal/BeforeTransactionCompletionProcessQueue.java +++ b/hibernate-core/src/main/java/org/hibernate/engine/internal/BeforeTransactionCompletionProcessQueue.java @@ -11,14 +11,14 @@ /** * Encapsulates behavior needed for before transaction processing */ -public class BeforeTransactionCompletionProcessQueue +class BeforeTransactionCompletionProcessQueue extends AbstractTransactionCompletionProcessQueue { - public BeforeTransactionCompletionProcessQueue(SharedSessionContractImplementor session) { + BeforeTransactionCompletionProcessQueue(SharedSessionContractImplementor session) { super( session ); } - public void beforeTransactionCompletion() { + void beforeTransactionCompletion() { BeforeCompletionCallback process; while ( (process = processes.poll()) != null ) { try { diff --git a/hibernate-core/src/main/java/org/hibernate/engine/internal/EntityEntryContext.java b/hibernate-core/src/main/java/org/hibernate/engine/internal/EntityEntryContext.java index cf38cd9b7d62..14f977b6a178 100644 --- a/hibernate-core/src/main/java/org/hibernate/engine/internal/EntityEntryContext.java +++ b/hibernate-core/src/main/java/org/hibernate/engine/internal/EntityEntryContext.java @@ -43,7 +43,7 @@ * * @author Steve Ebersole */ -public class EntityEntryContext { +class EntityEntryContext { private final transient PersistenceContext persistenceContext; @@ -63,7 +63,7 @@ public class EntityEntryContext { /** * Constructs a EntityEntryContext */ - public EntityEntryContext(PersistenceContext persistenceContext) { + EntityEntryContext(PersistenceContext persistenceContext) { this.persistenceContext = persistenceContext; } @@ -73,7 +73,7 @@ public EntityEntryContext(PersistenceContext persistenceContext) { * @param entity The entity * @param entityEntry The entry */ - public void addEntityEntry(Object entity, EntityEntry entityEntry) { + void addEntityEntry(Object entity, EntityEntry entityEntry) { // IMPORTANT!!!!! // add is called more than once of some entities. In such cases the first // call is simply setting up a "marker" to avoid infinite looping from reentrancy @@ -233,7 +233,7 @@ private void checkNotAssociatedWithOtherPersistenceContextIfMutable(ManagedEntit * * @return {@code true} if it is associated with this context */ - public boolean hasEntityEntry(Object entity) { + boolean hasEntityEntry(Object entity) { return getEntityEntry( entity ) != null; } @@ -244,7 +244,7 @@ public boolean hasEntityEntry(Object entity) { * * @return The associated {@link EntityEntry} */ - public EntityEntry getEntityEntry(Object entity) { + EntityEntry getEntityEntry(Object entity) { // locate a ManagedEntity for the entity, but only if it is associated with the same PersistenceContext. final var managedEntity = getAssociatedManagedEntity( entity ); // and get/return the EntityEntry from the ManagedEntry @@ -260,7 +260,7 @@ public EntityEntry getEntityEntry(Object entity) { * * @return The removed {@link EntityEntry} */ - public EntityEntry removeEntityEntry(Object entity) { + EntityEntry removeEntityEntry(Object entity) { // locate a ManagedEntity for the entity, but only if it is associated with the same PersistenceContext. // no need to check if the entity is a ManagedEntity that is associated with a different PersistenceContext final var managedEntity = getAssociatedManagedEntity( entity ); @@ -335,7 +335,7 @@ else if ( !isManagedEntity( entity ) ) { * * @return The safe array */ - public Map.Entry[] reentrantSafeEntityEntries() { + Map.Entry[] reentrantSafeEntityEntries() { if ( dirty ) { reentrantSafeEntries = new EntityEntryCrossRefImpl[count]; int i = 0; @@ -758,7 +758,7 @@ private static boolean canClearEntityEntryReference(EntityEntry entityEntry) { /** * Used in building the {@link #reentrantSafeEntityEntries()} entries */ - public interface EntityEntryCrossRef extends Map.Entry { + private interface EntityEntryCrossRef extends Map.Entry { /** * The entity * diff --git a/hibernate-core/src/main/java/org/hibernate/engine/internal/EntityEntryExtraStateHolder.java b/hibernate-core/src/main/java/org/hibernate/engine/internal/EntityEntryExtraStateHolder.java index cb5396d88f8c..6a53f3f79b0d 100644 --- a/hibernate-core/src/main/java/org/hibernate/engine/internal/EntityEntryExtraStateHolder.java +++ b/hibernate-core/src/main/java/org/hibernate/engine/internal/EntityEntryExtraStateHolder.java @@ -11,15 +11,15 @@ * * @author Emmanuel Bernard */ -public class EntityEntryExtraStateHolder implements EntityEntryExtraState { +class EntityEntryExtraStateHolder implements EntityEntryExtraState { private EntityEntryExtraState next; private Object[] deletedState; - public Object[] getDeletedState() { + Object[] getDeletedState() { return deletedState; } - public void setDeletedState(Object[] deletedState) { + void setDeletedState(Object[] deletedState) { this.deletedState = deletedState; } diff --git a/hibernate-core/src/main/java/org/hibernate/engine/internal/EntityEntryImpl.java b/hibernate-core/src/main/java/org/hibernate/engine/internal/EntityEntryImpl.java index 1cb39fee8178..f32adf748e9b 100644 --- a/hibernate-core/src/main/java/org/hibernate/engine/internal/EntityEntryImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/engine/internal/EntityEntryImpl.java @@ -508,6 +508,8 @@ public void serialize(ObjectOutputStream oos) throws IOException { /** * Custom deserialization routine used during deserialization * of a {@link PersistenceContext} for increased performance. + *

+ * This method is called reflectively by {@link EntityEntryContext}. * * @param ois The stream from which to read the entry * @param persistenceContext The context being deserialized diff --git a/hibernate-core/src/main/java/org/hibernate/engine/internal/NaturalIdResolutionsImpl.java b/hibernate-core/src/main/java/org/hibernate/engine/internal/NaturalIdResolutionsImpl.java index 030fe2f42fb5..16be10ec9430 100644 --- a/hibernate-core/src/main/java/org/hibernate/engine/internal/NaturalIdResolutionsImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/engine/internal/NaturalIdResolutionsImpl.java @@ -31,7 +31,7 @@ import static org.hibernate.engine.internal.CacheHelper.fromSharedCache; import static org.hibernate.engine.internal.NaturalIdLogging.NATURAL_ID_LOGGER; -public class NaturalIdResolutionsImpl implements NaturalIdResolutions, Serializable { +class NaturalIdResolutionsImpl implements NaturalIdResolutions, Serializable { private final StatefulPersistenceContext persistenceContext; private final ConcurrentHashMap resolutionsByEntity = new ConcurrentHashMap<>(); @@ -50,7 +50,7 @@ public class NaturalIdResolutionsImpl implements NaturalIdResolutions, Serializa * * @return The session */ - protected SharedSessionContractImplementor session() { + private SharedSessionContractImplementor session() { return persistenceContext.getSession(); } diff --git a/hibernate-core/src/main/java/org/hibernate/engine/internal/SessionEventListenerManagerImpl.java b/hibernate-core/src/main/java/org/hibernate/engine/internal/SessionEventListenerManagerImpl.java index 4aba25f3355e..c6853e977985 100644 --- a/hibernate-core/src/main/java/org/hibernate/engine/internal/SessionEventListenerManagerImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/engine/internal/SessionEventListenerManagerImpl.java @@ -5,13 +5,15 @@ package org.hibernate.engine.internal; import java.io.Serializable; -import java.util.Arrays; import java.util.List; -import java.util.Objects; import org.hibernate.SessionEventListener; import org.hibernate.engine.spi.SessionEventListenerManager; +import static java.lang.System.arraycopy; +import static java.util.Arrays.copyOf; +import static java.util.Objects.requireNonNull; + /** * @author Steve Ebersole */ @@ -21,28 +23,28 @@ public class SessionEventListenerManagerImpl implements SessionEventListenerMana public SessionEventListenerManagerImpl(SessionEventListener... initialListener) { //no need for defensive copies until the array is mutated: - this.listeners = initialListener; + listeners = initialListener; } public SessionEventListenerManagerImpl(List initialListener) { //no need for defensive copies until the array is mutated: - this.listeners = initialListener.toArray( new SessionEventListener[0] ); + listeners = initialListener.toArray( new SessionEventListener[0] ); } @Override public void addListener(final SessionEventListener... additionalListeners) { - Objects.requireNonNull( additionalListeners ); - final var existing = this.listeners; + requireNonNull( additionalListeners ); + final var existing = listeners; if ( existing == null ) { //Make a defensive copy as this array can be tracked back to API (user code) - this.listeners = Arrays.copyOf( additionalListeners, additionalListeners.length ); + listeners = copyOf( additionalListeners, additionalListeners.length ); } else { // Resize our existing array and add the new listeners final var newList = new SessionEventListener[ existing.length + additionalListeners.length ]; - System.arraycopy( existing, 0, newList, 0, existing.length ); - System.arraycopy( additionalListeners, 0, newList, existing.length, additionalListeners.length ); - this.listeners = newList; + arraycopy( existing, 0, newList, 0, existing.length ); + arraycopy( additionalListeners, 0, newList, existing.length, additionalListeners.length ); + listeners = newList; } } diff --git a/hibernate-core/src/main/java/org/hibernate/engine/internal/TwoPhaseLoad.java b/hibernate-core/src/main/java/org/hibernate/engine/internal/TwoPhaseLoad.java deleted file mode 100644 index 545735ddbdc9..000000000000 --- a/hibernate-core/src/main/java/org/hibernate/engine/internal/TwoPhaseLoad.java +++ /dev/null @@ -1,65 +0,0 @@ -/* - * SPDX-License-Identifier: Apache-2.0 - * Copyright Red Hat Inc. and Hibernate Authors - */ -package org.hibernate.engine.internal; - -import org.hibernate.LockMode; -import org.hibernate.engine.spi.EntityKey; -import org.hibernate.engine.spi.SharedSessionContractImplementor; -import org.hibernate.engine.spi.Status; -import org.hibernate.persister.entity.EntityPersister; - -import static org.hibernate.proxy.HibernateProxy.extractLazyInitializer; - -/** - * Functionality relating to the Hibernate two-phase loading process, that may be reused by persisters - * that do not use the Loader framework - * - * @author Gavin King - */ -public final class TwoPhaseLoad { - - private TwoPhaseLoad() { - } - - /** - * - * @param key The entity key - * @param object The entity instance - * @param persister The entity persister - * @param lockMode The lock mode - * @param version The version - * @param session The Session - */ - public static void addUninitializedCachedEntity( - final EntityKey key, - final Object object, - final EntityPersister persister, - final LockMode lockMode, - final Object version, - final SharedSessionContractImplementor session) { - final var persistenceContext = session.getPersistenceContextInternal(); - final var entityHolder = persistenceContext.addEntityHolder( key, object ); - final var entityEntry = persistenceContext.addEntry( - object, - Status.LOADING, - null, - 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 var lazyInitializer = extractLazyInitializer( proxy ); - assert lazyInitializer != null; - lazyInitializer.setImplementation( object ); - } - } -} diff --git a/hibernate-core/src/main/java/org/hibernate/loader/internal/CacheLoadHelper.java b/hibernate-core/src/main/java/org/hibernate/loader/internal/CacheLoadHelper.java index 40dd844df471..0711a5a00a7d 100644 --- a/hibernate-core/src/main/java/org/hibernate/loader/internal/CacheLoadHelper.java +++ b/hibernate-core/src/main/java/org/hibernate/loader/internal/CacheLoadHelper.java @@ -13,7 +13,6 @@ import org.hibernate.cache.spi.entry.ReferenceCacheEntryImpl; import org.hibernate.cache.spi.entry.StandardCacheEntryImpl; import org.hibernate.collection.spi.PersistentCollection; -import org.hibernate.engine.internal.TwoPhaseLoad; import org.hibernate.engine.spi.EntityEntry; import org.hibernate.engine.spi.EntityKey; import org.hibernate.engine.spi.SharedSessionContractImplementor; @@ -228,7 +227,7 @@ private static void makeEntityCircularReferenceSafe( entityHolder.setEntityEntry( entityEntry ); } else { - TwoPhaseLoad.addUninitializedCachedEntity( + addUninitializedCachedEntity( entityKey, entity, referenceCacheEntry.getSubclassPersister(), @@ -415,6 +414,46 @@ private static Object getFromSharedCache( return cachedEntry; } + /** + * + * @param key The entity key + * @param object The entity instance + * @param persister The entity persister + * @param lockMode The lock mode + * @param version The version + * @param session The Session + */ + static void addUninitializedCachedEntity( + final EntityKey key, + final Object object, + final EntityPersister persister, + final LockMode lockMode, + final Object version, + final SharedSessionContractImplementor session) { + final var persistenceContext = session.getPersistenceContextInternal(); + final var entityHolder = persistenceContext.addEntityHolder( key, object ); + final var entityEntry = persistenceContext.addEntry( + object, + Status.LOADING, + null, + 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 var lazyInitializer = extractLazyInitializer( proxy ); + assert lazyInitializer != null; + lazyInitializer.setImplementation( object ); + } + } + public record PersistenceContextEntry(Object entity, EntityStatus status) { public enum EntityStatus { MANAGED, diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/engine/spi/EntityEntryTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/engine/spi/EntityEntryTest.java index 345101e3d191..b92c4b2282cf 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/engine/spi/EntityEntryTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/engine/spi/EntityEntryTest.java @@ -5,7 +5,7 @@ package org.hibernate.orm.test.engine.spi; import org.hibernate.LockMode; -import org.hibernate.engine.internal.EntityEntryImpl; +import org.hibernate.engine.internal.MutableEntityEntryFactory; import org.hibernate.engine.spi.EntityEntry; import org.hibernate.engine.spi.PersistenceContext; import org.hibernate.engine.spi.SessionImplementor; @@ -91,8 +91,14 @@ public void testSerializationAndDeserializationKeepCorrectPackedAttributes() thr oos.flush(); InputStream is = new ByteArrayInputStream( baos.toByteArray() ); + final var entityEntryClass = + Class.forName( "org.hibernate.engine.internal.EntityEntryImpl" ); + + final var deserializeMethod = + entityEntryClass.getDeclaredMethod( "deserialize", + ObjectInputStream.class, PersistenceContext.class ); EntityEntry deserializedEntry = - EntityEntryImpl.deserialize( new ObjectInputStream( is ), + (EntityEntry) deserializeMethod.invoke( null, new ObjectInputStream( is ), getPersistenceContextMock() ); assertThat( deserializedEntry.getLockMode() ).isEqualTo( LockMode.OPTIMISTIC ); @@ -102,7 +108,7 @@ public void testSerializationAndDeserializationKeepCorrectPackedAttributes() thr } private EntityEntry createEntityEntry() { - return new EntityEntryImpl( + return MutableEntityEntryFactory.INSTANCE.createEntityEntry( Status.MANAGED, new Object[] {}, 1L, diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/naturalid/compound/CompoundNaturalIdCacheTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/naturalid/compound/CompoundNaturalIdCacheTest.java index 8715484ae6e0..a0b936a1e53c 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/naturalid/compound/CompoundNaturalIdCacheTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/naturalid/compound/CompoundNaturalIdCacheTest.java @@ -7,7 +7,6 @@ import org.hibernate.annotations.NaturalId; import org.hibernate.annotations.NaturalIdCache; import org.hibernate.cfg.AvailableSettings; -import org.hibernate.engine.internal.NaturalIdResolutionsImpl; import org.hibernate.stat.NaturalIdStatistics; import org.hibernate.stat.spi.StatisticsImplementor; @@ -63,8 +62,6 @@ public void setUp(SessionFactoryScope scope) { EntityWithSimpleNaturalId withSimpleNaturalIdEntity = new EntityWithSimpleNaturalId(); withSimpleNaturalIdEntity.setName( str ); session.persist( withSimpleNaturalIdEntity ); - NaturalIdResolutionsImpl naturalIdResolutions = (NaturalIdResolutionsImpl) session.getPersistenceContext() - .getNaturalIdResolutions(); } } );