diff --git a/hibernate-core/src/main/java/org/hibernate/action/internal/CollectionAction.java b/hibernate-core/src/main/java/org/hibernate/action/internal/CollectionAction.java index b5be548ddd07..3234fbc34a8a 100644 --- a/hibernate-core/src/main/java/org/hibernate/action/internal/CollectionAction.java +++ b/hibernate-core/src/main/java/org/hibernate/action/internal/CollectionAction.java @@ -7,7 +7,6 @@ import org.hibernate.action.spi.AfterTransactionCompletionProcess; import org.hibernate.action.spi.BeforeTransactionCompletionProcess; import org.hibernate.cache.CacheException; -import org.hibernate.cache.spi.access.CollectionDataAccess; import org.hibernate.cache.spi.access.SoftLock; import org.hibernate.collection.spi.PersistentCollection; import org.hibernate.engine.spi.ComparableExecutable; @@ -69,11 +68,11 @@ public void afterDeserialize(EventSource session) { @Override public final void beforeExecutions() throws CacheException { - // we need to obtain the lock before any actions are executed, since this may be an inverse="true" + // We need to obtain the lock before any actions are executed, since this may be an inverse="true" // bidirectional association, and it is one of the earlier entity actions which actually updates - // the database (this action is responsible for second-level cache invalidation only) + // the database. This action is responsible for second-level cache invalidation only. if ( persister.hasCache() ) { - final CollectionDataAccess cache = persister.getCacheAccessStrategy(); + final var cache = persister.getCacheAccessStrategy(); final Object ck = cache.generateCacheKey( key, persister, @@ -108,16 +107,9 @@ protected final CollectionPersister getPersister() { } protected final Object getKey() { - Object finalKey = key; - if ( key instanceof DelayedPostInsertIdentifier ) { - // need to look it up from the persistence-context - finalKey = session.getPersistenceContextInternal().getEntry( collection.getOwner() ).getId(); -// if ( finalKey == key ) { - // we may be screwed here since the collection action is about to execute - // and we do not know the final owner key value -// } - } - return finalKey; + return key instanceof DelayedPostInsertIdentifier + ? session.getPersistenceContextInternal().getEntry( collection.getOwner() ).getId() + : key; } @Override @@ -177,7 +169,7 @@ private CacheCleanupProcess(Object key, CollectionPersister persister, SoftLock @Override public void doAfterTransactionCompletion(boolean success, SharedSessionContractImplementor session) { - final CollectionDataAccess cache = persister.getCacheAccessStrategy(); + final var cache = persister.getCacheAccessStrategy(); final Object ck = cache.generateCacheKey( key, persister, diff --git a/hibernate-core/src/main/java/org/hibernate/action/internal/DelayedPostInsertIdentifier.java b/hibernate-core/src/main/java/org/hibernate/action/internal/DelayedPostInsertIdentifier.java index 67a801834b83..4aba138b7ee5 100644 --- a/hibernate-core/src/main/java/org/hibernate/action/internal/DelayedPostInsertIdentifier.java +++ b/hibernate-core/src/main/java/org/hibernate/action/internal/DelayedPostInsertIdentifier.java @@ -45,11 +45,11 @@ public DelayedPostInsertIdentifier() { } @Override - public boolean equals(Object o) { - if ( this == o ) { + public boolean equals(Object object) { + if ( this == object ) { return true; } - else if ( !(o instanceof DelayedPostInsertIdentifier that) ) { + else if ( !(object instanceof DelayedPostInsertIdentifier that) ) { return false; } else { diff --git a/hibernate-core/src/main/java/org/hibernate/action/internal/EntityDeleteAction.java b/hibernate-core/src/main/java/org/hibernate/action/internal/EntityDeleteAction.java index 935e8031ee33..385e0a6d4e3e 100644 --- a/hibernate-core/src/main/java/org/hibernate/action/internal/EntityDeleteAction.java +++ b/hibernate-core/src/main/java/org/hibernate/action/internal/EntityDeleteAction.java @@ -106,15 +106,7 @@ public void execute() throws HibernateException { final boolean veto = isInstanceLoaded() && preDelete(); - final var naturalIdMapping = persister.getNaturalIdMapping(); - if ( naturalIdMapping != null ) { - naturalIdValues = session.getPersistenceContextInternal().getNaturalIdResolutions() - .removeLocalResolution( - getId(), - naturalIdMapping.extractNaturalIdFromEntityState( state ), - persister - ); - } + handleNaturalIdResolutions( persister, session ); final Object ck = lockCacheItem(); @@ -145,6 +137,18 @@ public void execute() throws HibernateException { } } + private void handleNaturalIdResolutions(EntityPersister persister, EventSource session) { + final var naturalIdMapping = persister.getNaturalIdMapping(); + if ( naturalIdMapping != null ) { + naturalIdValues = session.getPersistenceContextInternal().getNaturalIdResolutions() + .removeLocalResolution( + getId(), + naturalIdMapping.extractNaturalIdFromEntityState( state ), + persister + ); + } + } + protected Object getCurrentVersion() { final var persister = getPersister(); return persister.isVersionPropertyGenerated() @@ -176,7 +180,7 @@ protected void postDeleteLoaded( persistenceContext.removeEntityHolder( key ); removeCacheItem( ck ); persistenceContext.getNaturalIdResolutions() - .removeSharedResolution( id, naturalIdValues, persister, true); + .removeSharedResolution( id, naturalIdValues, persister, true ); postDelete(); } diff --git a/hibernate-core/src/main/java/org/hibernate/action/internal/EntityInsertAction.java b/hibernate-core/src/main/java/org/hibernate/action/internal/EntityInsertAction.java index 4b5e222a74c6..c3a9efcbdb72 100644 --- a/hibernate-core/src/main/java/org/hibernate/action/internal/EntityInsertAction.java +++ b/hibernate-core/src/main/java/org/hibernate/action/internal/EntityInsertAction.java @@ -163,8 +163,8 @@ protected void putCacheIfNecessary() { final var session = getSession(); if ( isCachePutEnabled( persister, session ) ) { final var factory = session.getFactory(); - final var ce = persister.buildCacheEntry( getInstance(), getState(), version, session ); - cacheEntry = persister.getCacheEntryStructure().structure( ce ); + final var cacheEntry = persister.buildCacheEntry( getInstance(), getState(), version, session ); + this.cacheEntry = persister.getCacheEntryStructure().structure( cacheEntry ); final var cache = persister.getCacheAccessStrategy(); final Object ck = cache.generateCacheKey( getId(), persister, factory, session.getTenantIdentifier() ); final boolean put = cacheInsert( persister, ck ); diff --git a/hibernate-core/src/main/java/org/hibernate/action/internal/EntityUpdateAction.java b/hibernate-core/src/main/java/org/hibernate/action/internal/EntityUpdateAction.java index 57651fcf2984..b25d92bf9cc1 100644 --- a/hibernate-core/src/main/java/org/hibernate/action/internal/EntityUpdateAction.java +++ b/hibernate-core/src/main/java/org/hibernate/action/internal/EntityUpdateAction.java @@ -12,6 +12,7 @@ import org.hibernate.cache.spi.access.SoftLock; import org.hibernate.engine.spi.CachedNaturalIdValueSource; import org.hibernate.engine.spi.EntityEntry; +import org.hibernate.engine.spi.PersistenceContext; import org.hibernate.engine.spi.SharedSessionContractImplementor; import org.hibernate.engine.spi.Status; import org.hibernate.event.monitor.spi.EventMonitor; @@ -82,13 +83,15 @@ public EntityUpdateAction( this.hasDirtyCollection = hasDirtyCollection; this.rowId = rowId; - this.naturalIdMapping = persister.getNaturalIdMapping(); + naturalIdMapping = persister.getNaturalIdMapping(); if ( naturalIdMapping == null ) { previousNaturalIdValues = null; } else { previousNaturalIdValues = - determinePreviousNaturalIdValues( persister, naturalIdMapping, id, previousState, session ); + previousState == null + ? session.getPersistenceContextInternal().getNaturalIdSnapshot( id, persister ) + : naturalIdMapping.extractNaturalIdFromEntityState( previousState ); session.getPersistenceContextInternal().getNaturalIdResolutions().manageLocalResolution( id, naturalIdMapping.extractNaturalIdFromEntityState( state ), @@ -98,17 +101,6 @@ public EntityUpdateAction( } } - private static Object determinePreviousNaturalIdValues( - EntityPersister persister, - NaturalIdMapping naturalIdMapping, - Object id, - Object[] previousState, - SharedSessionContractImplementor session) { - return previousState == null - ? session.getPersistenceContextInternal().getNaturalIdSnapshot( id, persister ) - : naturalIdMapping.extractNaturalIdFromEntityState( previousState ); - } - protected Object[] getState() { return state; } @@ -178,14 +170,15 @@ public void execute() throws HibernateException { finally { eventMonitor.completeEntityUpdateEvent( event, id, persister.getEntityName(), success, session ); } - final var entry = session.getPersistenceContextInternal().getEntry( instance ); + final var persistenceContext = session.getPersistenceContextInternal(); + final var entry = persistenceContext.getEntry( instance ); if ( entry == null ) { throw new AssertionFailure( "possible non thread safe access to session" ); } handleGeneratedProperties( entry, generatedValues ); handleDeleted( entry ); updateCacheItem( previousVersion, ck, entry ); - handleNaturalIdResolutions( persister, session, id ); + handleNaturalIdResolutions( persister, persistenceContext, id ); postUpdate(); final var statistics = session.getFactory().getStatistics(); @@ -195,9 +188,9 @@ public void execute() throws HibernateException { } } - protected void handleNaturalIdResolutions(EntityPersister persister, SharedSessionContractImplementor session, Object id) { + protected void handleNaturalIdResolutions(EntityPersister persister, PersistenceContext context, Object id) { if ( naturalIdMapping != null ) { - session.getPersistenceContextInternal().getNaturalIdResolutions().manageSharedResolution( + context.getNaturalIdResolutions().manageSharedResolution( id, naturalIdMapping.extractNaturalIdFromEntityState( state ), previousNaturalIdValues, @@ -216,8 +209,8 @@ protected void updateCacheItem(Object previousVersion, Object ck, EntityEntry en } else if ( session.getCacheMode().isPutEnabled() ) { //TODO: inefficient if that cache is just going to ignore the updated state! - final var ce = persister.buildCacheEntry( getInstance(), state, nextVersion, getSession() ); - cacheEntry = persister.getCacheEntryStructure().structure( ce ); + final var cacheEntry = persister.buildCacheEntry( getInstance(), state, nextVersion, getSession() ); + this.cacheEntry = persister.getCacheEntryStructure().structure( cacheEntry ); final boolean put = updateCache( persister, previousVersion, ck ); final var statistics = session.getFactory().getStatistics(); @@ -279,9 +272,9 @@ protected void handleDeleted(EntityEntry entry) { final boolean isImpliedOptimisticLocking = !entityMetamodel.isVersioned() && entityMetamodel.getOptimisticLockStyle().isAllOrDirty(); if ( isImpliedOptimisticLocking && entry.getLoadedState() != null ) { - // The entity will be deleted and because we are going to create a delete statement + // The entity will be deleted, and because we are going to create a delete statement // that uses all the state values in the where clause, the entry state needs to be - // updated otherwise the statement execution will not delete any row (see HHH-15218). + // updated. Otherwise, the statement execution will not delete any row (see HHH-15218). entry.postUpdate( getInstance(), state, nextVersion ); } } diff --git a/hibernate-core/src/main/java/org/hibernate/action/internal/UnresolvedEntityInsertActions.java b/hibernate-core/src/main/java/org/hibernate/action/internal/UnresolvedEntityInsertActions.java index edebc3979ca1..5e9a125ab709 100644 --- a/hibernate-core/src/main/java/org/hibernate/action/internal/UnresolvedEntityInsertActions.java +++ b/hibernate-core/src/main/java/org/hibernate/action/internal/UnresolvedEntityInsertActions.java @@ -226,7 +226,7 @@ public Set resolveDependentActions(Object managedEnt infoString( entityEntry.getEntityName(), entityEntry.getId() ) ); } - // dependentAction only depended on managedEntity.. + // dependentAction only depended on managedEntity dependenciesByAction.remove( dependentAction ); resolvedActions.add( dependentAction ); } @@ -252,18 +252,18 @@ public void clear() { @Override public String toString() { - final var sb = new StringBuilder( getClass().getSimpleName() ).append( '[' ); + final var representation = new StringBuilder( getClass().getSimpleName() ).append( '[' ); for ( var entry : dependenciesByAction.entrySet() ) { final AbstractEntityInsertAction insert = entry.getKey(); final NonNullableTransientDependencies dependencies = entry.getValue(); - sb.append( "[insert=" ) + representation.append( "[insert=" ) .append( insert ) .append( " dependencies=[" ) .append( dependencies.toLoggableString( insert.getSession() ) ) .append( "]" ); } - sb.append( ']'); - return sb.toString(); + representation.append( ']'); + return representation.toString(); } /** diff --git a/hibernate-core/src/main/java/org/hibernate/cache/internal/EnabledCaching.java b/hibernate-core/src/main/java/org/hibernate/cache/internal/EnabledCaching.java index fba56d0c3dba..219882499943 100644 --- a/hibernate-core/src/main/java/org/hibernate/cache/internal/EnabledCaching.java +++ b/hibernate-core/src/main/java/org/hibernate/cache/internal/EnabledCaching.java @@ -348,8 +348,8 @@ private void evictNaturalIdData(NavigableRole rootEntityRole, NaturalIdDataAcces @Override public boolean containsCollection(String role, Object ownerIdentifier) { - final CollectionPersister persister = getCollectionDescriptor( role ); - final CollectionDataAccess cacheAccess = persister.getCacheAccessStrategy(); + final var persister = getCollectionDescriptor( role ); + final var cacheAccess = persister.getCacheAccessStrategy(); if ( cacheAccess != null ) { final Object cacheKey = cacheAccess.generateCacheKey( ownerIdentifier, persister, sessionFactory, null ); diff --git a/hibernate-core/src/main/java/org/hibernate/engine/spi/ActionQueue.java b/hibernate-core/src/main/java/org/hibernate/engine/spi/ActionQueue.java index b65b407a8df3..12aa20a18918 100644 --- a/hibernate-core/src/main/java/org/hibernate/engine/spi/ActionQueue.java +++ b/hibernate-core/src/main/java/org/hibernate/engine/spi/ActionQueue.java @@ -12,7 +12,6 @@ import java.util.BitSet; import java.util.HashSet; import java.util.IdentityHashMap; -import java.util.Iterator; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; @@ -45,10 +44,7 @@ import org.hibernate.event.spi.EventSource; import org.hibernate.internal.CoreLogging; import org.hibernate.internal.CoreMessageLogger; -import org.hibernate.metamodel.mapping.PluralAttributeMapping; import org.hibernate.metamodel.mapping.internal.EntityCollectionPart; -import org.hibernate.persister.entity.EntityPersister; -import org.hibernate.proxy.LazyInitializer; import org.hibernate.type.CollectionType; import org.hibernate.type.ComponentType; import org.hibernate.type.EntityType; @@ -238,10 +234,10 @@ public ActionQueue(SessionImplementor session) { } public void clear() { - for ( OrderedActions value : ORDERED_OPERATIONS ) { - final ExecutableList list = value.getActions( this ); - if ( list != null ) { - list.clear(); + for ( var value : ORDERED_OPERATIONS ) { + final var queue = value.getActions( this ); + if ( queue != null ) { + queue.clear(); } } if ( unresolvedInsertions != null ) { @@ -375,7 +371,7 @@ public void addAction(final CollectionRemoveAction action) { .isDeletedOrGone() ) { // We need to check if this collection's owner is an orphan being removed, // which case we should remove the collection first to avoid constraint violations - for ( OrphanRemovalAction orphanRemoval : orphanRemovals ) { + for ( var orphanRemoval : orphanRemovals ) { if ( orphanRemoval.getInstance() == action.getAffectedOwner() ) { OrderedActions.OrphanCollectionRemoveAction.ensureInitialized( this ); orphanCollectionRemovals.add( action ); @@ -417,20 +413,22 @@ public void addAction(BulkOperationCleanupAction action) { } private void registerCleanupActions(Executable executable) { - if ( executable.getBeforeTransactionCompletionProcess() != null ) { + final var beforeTransactionCompletion = executable.getBeforeTransactionCompletionProcess(); + if ( beforeTransactionCompletion != null ) { if ( beforeTransactionProcesses == null ) { beforeTransactionProcesses = new BeforeTransactionCompletionProcessQueue( session ); } - beforeTransactionProcesses.register( executable.getBeforeTransactionCompletionProcess() ); + beforeTransactionProcesses.register( beforeTransactionCompletion ); } if ( getSessionFactoryOptions().isQueryCacheEnabled() ) { invalidateSpaces( executable.getPropertySpaces() ); } - if ( executable.getAfterTransactionCompletionProcess() != null ) { + final var afterTransactionCompletion = executable.getAfterTransactionCompletionProcess(); + if ( afterTransactionCompletion != null ) { if ( afterTransactionProcesses == null ) { afterTransactionProcesses = new AfterTransactionCompletionProcessQueue( session ); } - afterTransactionProcesses.register( executable.getAfterTransactionCompletionProcess() ); + afterTransactionProcesses.register( afterTransactionCompletion ); } } @@ -492,10 +490,10 @@ public void executeInserts() throws HibernateException { */ public void executeActions() throws HibernateException { if ( hasUnresolvedEntityInsertActions() ) { - final AbstractEntityInsertAction insertAction = + final var insertAction = unresolvedInsertions.getDependentEntityInsertActions() .iterator().next(); - final NonNullableTransientDependencies transientEntities = insertAction.findNonNullableTransientEntities(); + final var transientEntities = insertAction.findNonNullableTransientEntities(); final Object transientEntity = transientEntities.getNonNullableTransientEntities().iterator().next(); final String path = transientEntities.getNonNullableTransientPropertyPaths( transientEntity ).iterator().next(); final String transientEntityName = session.bestGuessEntityName( transientEntity ); @@ -509,7 +507,7 @@ public void executeActions() throws HibernateException { path ); } - for ( OrderedActions action : ORDERED_OPERATIONS ) { + for ( var action : ORDERED_OPERATIONS ) { executeActions( action.getActions( this ) ); } } @@ -528,7 +526,7 @@ public void prepareActions() throws HibernateException { private void prepareActions(@Nullable ExecutableList queue) throws HibernateException { if ( queue != null ) { - for ( Executable executable : queue ) { + for ( var executable : queue ) { executable.beforeExecutions(); } } @@ -586,9 +584,9 @@ public boolean areTablesToBeUpdated(Set tables) { if ( tables.isEmpty() ) { return false; } - for ( OrderedActions action : ORDERED_OPERATIONS ) { - final ExecutableList list = action.getActions( this ); - if ( areTablesToBeUpdated( list, tables ) ) { + for ( var action : ORDERED_OPERATIONS ) { + final var queue = action.getActions( this ); + if ( areTablesToBeUpdated( queue, tables ) ) { return true; } } @@ -598,25 +596,24 @@ public boolean areTablesToBeUpdated(Set tables) { return areTablesToBeUpdated( unresolvedInsertions, tables ); } - private static boolean areTablesToBeUpdated(@Nullable ExecutableList actions, Set tableSpaces) { - if ( actions == null || actions.isEmpty() ) { + private static boolean areTablesToBeUpdated(@Nullable ExecutableList queue, Set tableSpaces) { + if ( queue == null || queue.isEmpty() ) { return false; } - - for ( Serializable actionSpace : actions.getQuerySpaces() ) { - if ( tableSpaces.contains( actionSpace ) ) { - LOG.tracef( "Changes must be flushed to space: %s", actionSpace ); - return true; + else { + for ( var actionSpace : queue.getQuerySpaces() ) { + if ( tableSpaces.contains( actionSpace ) ) { + LOG.tracef( "Changes must be flushed to space: %s", actionSpace ); + return true; + } } + return false; } - - return false; } private static boolean areTablesToBeUpdated(UnresolvedEntityInsertActions actions, Set tableSpaces) { - for ( Executable action : actions.getDependentEntityInsertActions() ) { - final Serializable[] spaces = action.getPropertySpaces(); - for ( Serializable space : spaces ) { + for ( var action : actions.getDependentEntityInsertActions() ) { + for ( var space : action.getPropertySpaces() ) { if ( tableSpaces.contains( space ) ) { LOG.tracef( "Changes must be flushed to space: %s", space ); return true; @@ -629,51 +626,50 @@ private static boolean areTablesToBeUpdated(UnresolvedEntityInsertActions action /** * Perform {@link Executable#execute()} on each element of the list * - * @param list The list of Executable elements to be performed + * @param queue The list of Executable elements to be performed * */ - private void executeActions(@Nullable ExecutableList list) + private void executeActions(@Nullable ExecutableList queue) throws HibernateException { - if ( list == null || list.isEmpty() ) { - return; - } - // todo : consider ways to improve the double iteration of Executables here: - // 1) we explicitly iterate list here to perform Executable#execute() - // 2) ExecutableList#getQuerySpaces also iterates the Executables to collect query spaces. - try { - for ( ComparableExecutable executable : list ) { - try { - executable.execute(); - } - finally { - if ( executable.getBeforeTransactionCompletionProcess() != null ) { - if ( beforeTransactionProcesses == null ) { - beforeTransactionProcesses = new BeforeTransactionCompletionProcessQueue( session ); - } - beforeTransactionProcesses.register( executable.getBeforeTransactionCompletionProcess() ); + if ( queue != null && !queue.isEmpty() ) { + // todo : consider ways to improve the double iteration of Executables here: + // 1) we explicitly iterate list here to perform Executable#execute() + // 2) ExecutableList#getQuerySpaces also iterates the Executables to collect query spaces. + try { + for ( var executable : queue ) { + try { + executable.execute(); } - if ( executable.getAfterTransactionCompletionProcess() != null ) { - if ( afterTransactionProcesses == null ) { - afterTransactionProcesses = new AfterTransactionCompletionProcessQueue( session ); + finally { + final var beforeTransactionCompletion = executable.getBeforeTransactionCompletionProcess(); + if ( beforeTransactionCompletion != null ) { + if ( beforeTransactionProcesses == null ) { + beforeTransactionProcesses = new BeforeTransactionCompletionProcessQueue( session ); + } + beforeTransactionProcesses.register( beforeTransactionCompletion ); + } + final var afterTransactionCompletion = executable.getAfterTransactionCompletionProcess(); + if ( afterTransactionCompletion != null ) { + if ( afterTransactionProcesses == null ) { + afterTransactionProcesses = new AfterTransactionCompletionProcessQueue( session ); + } + afterTransactionProcesses.register( afterTransactionCompletion ); } - afterTransactionProcesses.register( executable.getAfterTransactionCompletionProcess() ); } } } - } - finally { - if ( getSessionFactoryOptions().isQueryCacheEnabled() ) { - // Strictly speaking, only a subset of the list may have been processed if a RuntimeException occurs. - // We still invalidate all spaces. I don't see this as a big deal - after all, RuntimeExceptions are - // unexpected. - invalidateSpaces( list.getQuerySpaces().toArray(new String[0]) ); + finally { + if ( getSessionFactoryOptions().isQueryCacheEnabled() ) { + // Strictly speaking, only a subset of the list may have been processed if a RuntimeException occurs. + // We still invalidate all spaces. I don't see this as a big deal - after all, RuntimeExceptions are + // unexpected. + invalidateSpaces( queue.getQuerySpaces().toArray( new String[0] ) ); + } } - // @NonNull String @Nullable [] - array nullable, elements not - // @Nullable String @NonNull [] - elements nullable, array not - } - list.clear(); - session.getJdbcCoordinator().executeBatch(); + queue.clear(); + session.getJdbcCoordinator().executeBatch(); + } } /** @@ -695,7 +691,7 @@ public > void execute(E executable) { */ private void invalidateSpaces(String @Nullable [] spaces) { if ( spaces != null && spaces.length > 0 ) { - for ( String space : spaces ) { + for ( var space : spaces ) { if ( afterTransactionProcesses == null ) { afterTransactionProcesses = new AfterTransactionCompletionProcessQueue( session ); } @@ -725,8 +721,8 @@ public String toString() { + "]"; } - private static String toString(@Nullable ExecutableList q) { - return q == null ? "ExecutableList{size=0}" : q.toString(); + private static String toString(@Nullable ExecutableList queue) { + return queue == null ? "ExecutableList{size=0}" : queue.toString(); } public int numberOfCollectionRemovals() { @@ -742,9 +738,9 @@ public int numberOfCollectionCreations() { } public int numberOfDeletions() { - final int del = deletions == null ? 0 : deletions.size(); - final int orph = orphanRemovals == null ? 0 : orphanRemovals.size(); - return del + orph; + final int deletes = deletions == null ? 0 : deletions.size(); + final int orphans = orphanRemovals == null ? 0 : orphanRemovals.size(); + return deletes + orphans; } public int numberOfUpdates() { @@ -864,16 +860,16 @@ public boolean hasAnyQueuedActions() { || nonempty( collectionCreations ); } - private boolean nonempty(@Nullable ExecutableList list) { - return list != null && !list.isEmpty(); + private boolean nonempty(@Nullable ExecutableList queue) { + return queue != null && !queue.isEmpty(); } public void unScheduleUnloadedDeletion(Object newEntity) { - final EntityPersister entityPersister = session.getEntityPersister( null, newEntity ); + final var entityPersister = session.getEntityPersister( null, newEntity ); final Object identifier = entityPersister.getIdentifier( newEntity, session ); if ( deletions != null ) { for ( int i = 0; i < deletions.size(); i++ ) { - final EntityDeleteAction action = deletions.get( i ); + final var action = deletions.get( i ); if ( action.getInstance() == null && action.getEntityName().equals( entityPersister.getEntityName() ) && entityPersister.getIdentifierMapping().areEqual( action.getId(), identifier, session ) ) { @@ -888,15 +884,13 @@ public void unScheduleUnloadedDeletion(Object newEntity) { } public void unScheduleDeletion(EntityEntry entry, Object rescuedEntity) { - final LazyInitializer lazyInitializer = extractLazyInitializer( rescuedEntity ); - if ( lazyInitializer != null ) { - if ( !lazyInitializer.isUninitialized() ) { - rescuedEntity = lazyInitializer.getImplementation( session ); - } + final var lazyInitializer = extractLazyInitializer( rescuedEntity ); + if ( lazyInitializer != null && !lazyInitializer.isUninitialized() ) { + rescuedEntity = lazyInitializer.getImplementation( session ); } if ( deletions != null ) { for ( int i = 0; i < deletions.size(); i++ ) { - final EntityDeleteAction action = deletions.get( i ); + final var action = deletions.get( i ); if ( action.getInstance() == rescuedEntity ) { deletions.remove( i ); return; @@ -905,7 +899,7 @@ public void unScheduleDeletion(EntityEntry entry, Object rescuedEntity) { } if ( orphanRemovals != null ) { for ( int i = 0; i < orphanRemovals.size(); i++ ) { - final EntityDeleteAction action = orphanRemovals.get( i ); + final var action = orphanRemovals.get( i ); if ( action.getInstance() == rescuedEntity ) { orphanRemovals.remove( i ); return; @@ -928,14 +922,14 @@ public void serialize(ObjectOutputStream oos) throws IOException { } unresolvedInsertions.serialize( oos ); - for ( OrderedActions action : ORDERED_OPERATIONS ) { - final ExecutableList l = action.getActions( this ); - if ( l == null ) { + for ( var action : ORDERED_OPERATIONS ) { + final var queue = action.getActions( this ); + if ( queue == null ) { oos.writeBoolean( false ); } else { oos.writeBoolean( true ); - l.writeExternal( oos ); + queue.writeExternal( oos ); } } } @@ -955,35 +949,31 @@ public static ActionQueue deserialize(ObjectInputStream ois, EventSource session if ( traceEnabled ) { LOG.trace( "Deserializing action-queue" ); } - ActionQueue rtn = new ActionQueue( session ); - - rtn.unresolvedInsertions = UnresolvedEntityInsertActions.deserialize( ois, session ); - - for ( OrderedActions action : ORDERED_OPERATIONS ) { - ExecutableList l = action.getActions( rtn ); - boolean notNull = ois.readBoolean(); + final var actionQueue = new ActionQueue( session ); + actionQueue.unresolvedInsertions = UnresolvedEntityInsertActions.deserialize( ois, session ); + for ( var action : ORDERED_OPERATIONS ) { + final boolean notNull = ois.readBoolean(); if ( notNull ) { - if ( l == null ) { - //sorry.. trying hard to avoid generic initializations mess. - action.ensureInitialized( rtn ); - l = action.getActions( rtn ); + var queue = action.getActions( actionQueue ); + if ( queue == null ) { + // trying hard to avoid generic initializations mess + action.ensureInitialized( actionQueue ); + queue = action.getActions( actionQueue ); } - l.readExternal( ois ); - + queue.readExternal( ois ); if ( traceEnabled ) { - LOG.tracev( "Deserialized [{0}] entries", l.size() ); + LOG.tracev( "Deserialized [{0}] entries", queue.size() ); } - l.afterDeserialize( session ); + queue.afterDeserialize( session ); } } - - return rtn; + return actionQueue; } private abstract static class AbstractTransactionCompletionProcessQueue { protected SessionImplementor session; - // Concurrency handling required when transaction completion process is dynamically registered - // inside event listener (HHH-7478). + // Concurrency handling required when transaction completion process + // is dynamically registered inside the event listener (HHH-7478). protected ConcurrentLinkedQueue<@NonNull T> processes = new ConcurrentLinkedQueue<>(); private AbstractTransactionCompletionProcessQueue(SessionImplementor session) { @@ -1057,7 +1047,7 @@ public void afterTransactionCompletion(boolean success) { } } - final SessionFactoryImplementor factory = session.getFactory(); + final var factory = session.getFactory(); if ( factory.getSessionFactoryOptions().isQueryCacheEnabled() ) { factory.getCache().getTimestampsCache() .invalidate( querySpacesToInvalidate.toArray(new String[0]), session ); @@ -1126,7 +1116,7 @@ private void buildDirectDependencies(IdentityHashMap insertI private void propagateChildDependencies() { if ( outgoingDependencies != null ) { - for ( InsertInfo childDependency : outgoingDependencies ) { + for ( var childDependency : outgoingDependencies ) { if ( childDependency.transitiveIncomingDependencies == null ) { childDependency.transitiveIncomingDependencies = new HashSet<>(); } @@ -1138,7 +1128,7 @@ private void propagateChildDependencies() { private void buildTransitiveDependencies(Set visited) { if ( transitiveIncomingDependencies != null ) { visited.addAll( transitiveIncomingDependencies ); - for ( InsertInfo insertInfo : transitiveIncomingDependencies.toArray(new InsertInfo[0]) ) { + for ( var insertInfo : transitiveIncomingDependencies.toArray( new InsertInfo[0] ) ) { insertInfo.addTransitiveDependencies(this, visited); } visited.clear(); @@ -1147,8 +1137,8 @@ private void buildTransitiveDependencies(Set visited) { private void addTransitiveDependencies(InsertInfo origin, Set visited) { if ( transitiveIncomingDependencies != null ) { - for ( InsertInfo insertInfo : transitiveIncomingDependencies ) { - if ( visited.add(insertInfo) ) { + for ( var insertInfo : transitiveIncomingDependencies ) { + if ( visited.add( insertInfo ) ) { origin.transitiveIncomingDependencies.add( insertInfo ); insertInfo.addTransitiveDependencies( origin, visited ); } @@ -1157,67 +1147,66 @@ private void addTransitiveDependencies(InsertInfo origin, Set visite } private void addDirectDependency(Type type, @Nullable Object value, IdentityHashMap insertInfosByEntity) { - if ( value == null ) { - return; - } - if ( type instanceof EntityType entityType ) { - final InsertInfo insertInfo = insertInfosByEntity.get( value ); - if ( insertInfo != null ) { - if ( entityType.isOneToOne() - && entityType.getForeignKeyDirection() == ForeignKeyDirection.TO_PARENT ) { - if ( !entityType.isReferenceToPrimaryKey() ) { - if ( outgoingDependencies == null ) { - outgoingDependencies = new HashSet<>(); + if ( value != null ) { + if ( type instanceof EntityType entityType ) { + final InsertInfo insertInfo = insertInfosByEntity.get( value ); + if ( insertInfo != null ) { + if ( entityType.isOneToOne() + && entityType.getForeignKeyDirection() == ForeignKeyDirection.TO_PARENT ) { + if ( !entityType.isReferenceToPrimaryKey() ) { + if ( outgoingDependencies == null ) { + outgoingDependencies = new HashSet<>(); + } + outgoingDependencies.add( insertInfo ); } - outgoingDependencies.add( insertInfo ); } - } - else { - if ( transitiveIncomingDependencies == null ) { - transitiveIncomingDependencies = new HashSet<>(); + else { + if ( transitiveIncomingDependencies == null ) { + transitiveIncomingDependencies = new HashSet<>(); + } + transitiveIncomingDependencies.add( insertInfo ); } - transitiveIncomingDependencies.add( insertInfo ); } } - } - else if ( type instanceof CollectionType collectionType ) { - final PluralAttributeMapping pluralAttributeMapping = - insertAction.getSession().getFactory().getMappingMetamodel() - .getCollectionDescriptor( collectionType.getRole() ) - .getAttributeMapping(); - // We only care about mappedBy one-to-many associations, because for these, - // the elements depend on the collection owner - if ( pluralAttributeMapping.getCollectionDescriptor().isOneToMany() - && pluralAttributeMapping.getElementDescriptor() instanceof EntityCollectionPart ) { - final Iterator elementsIterator = collectionType.getElementsIterator( value ); - while ( elementsIterator.hasNext() ) { - final Object element = elementsIterator.next(); - final InsertInfo insertInfo = insertInfosByEntity.get( element ); - if ( insertInfo != null ) { - if ( outgoingDependencies == null ) { - outgoingDependencies = new HashSet<>(); + else if ( type instanceof CollectionType collectionType ) { + final var pluralAttributeMapping = + insertAction.getSession().getFactory().getMappingMetamodel() + .getCollectionDescriptor( collectionType.getRole() ) + .getAttributeMapping(); + // We only care about mappedBy one-to-many associations, because for these, + // the elements depend on the collection owner + if ( pluralAttributeMapping.getCollectionDescriptor().isOneToMany() + && pluralAttributeMapping.getElementDescriptor() instanceof EntityCollectionPart ) { + final var elementsIterator = collectionType.getElementsIterator( value ); + while ( elementsIterator.hasNext() ) { + final Object element = elementsIterator.next(); + final InsertInfo insertInfo = insertInfosByEntity.get( element ); + if ( insertInfo != null ) { + if ( outgoingDependencies == null ) { + outgoingDependencies = new HashSet<>(); + } + outgoingDependencies.add( insertInfo ); } - outgoingDependencies.add( insertInfo ); } } } - } - else if ( type instanceof ComponentType compositeType ) { - // Support recursive checks of composite type properties for associations and collections. - final SharedSessionContractImplementor session = insertAction.getSession(); - final Object[] componentValues = compositeType.getPropertyValues( value, session ); - for ( int j = 0; j < componentValues.length; ++j ) { - final Type componentValueType = compositeType.getSubtypes()[j]; - final Object componentValue = componentValues[j]; - addDirectDependency( componentValueType, componentValue, insertInfosByEntity ); + else if ( type instanceof ComponentType compositeType ) { + // Support recursive checks of composite type properties for associations and collections. + final var session = insertAction.getSession(); + final Object[] componentValues = compositeType.getPropertyValues( value, session ); + for ( int j = 0; j < componentValues.length; ++j ) { + final Type componentValueType = compositeType.getSubtypes()[j]; + final Object componentValue = componentValues[j]; + addDirectDependency( componentValueType, componentValue, insertInfosByEntity ); + } } } } @Override - public boolean equals(@Nullable Object o) { - return this == o - || o instanceof InsertInfo that + public boolean equals(@Nullable Object object) { + return this == object + || object instanceof InsertInfo that && insertAction.equals( that.insertAction ); } @@ -1250,8 +1239,8 @@ public void sort(List insertions) { new IdentityHashMap<>( insertInfos.length ); // Construct insert infos and build a map for that, keyed by entity instance for (int i = 0; i < insertInfoCount; i++) { - final AbstractEntityInsertAction insertAction = insertions.get(i); - final InsertInfo insertInfo = new InsertInfo( insertAction, i ); + final var insertAction = insertions.get(i); + final var insertInfo = new InsertInfo( insertAction, i ); insertInfosByEntity.put( insertAction.getInstance(), insertInfo ); insertInfos[i] = insertInfo; } @@ -1272,7 +1261,7 @@ public void sort(List insertions) { insertInfo.buildTransitiveDependencies( visited ); final String entityName = insertInfo.insertAction.getPersister().getEntityName(); - EntityInsertGroup entityInsertGroup = insertInfosByEntityName.get( entityName ); + var entityInsertGroup = insertInfosByEntityName.get( entityName ); if (entityInsertGroup == null) { entityInsertGroup = new EntityInsertGroup( entityName ); insertInfosByEntityName.put( entityName, entityInsertGroup ); @@ -1286,9 +1275,9 @@ public void sort(List insertions) { int lastScheduleSize; do { lastScheduleSize = scheduledEntityNames.size(); - final Iterator iterator = insertInfosByEntityName.values().iterator(); + final var iterator = insertInfosByEntityName.values().iterator(); while ( iterator.hasNext() ) { - final EntityInsertGroup insertGroup = iterator.next(); + final var insertGroup = iterator.next(); if ( scheduledEntityNames.containsAll( insertGroup.dependentEntityNames) ) { schedulePosition = schedule( insertInfos, insertGroup.insertInfos, schedulePosition ); scheduledEntityNames.add( insertGroup.entityName ); @@ -1303,8 +1292,8 @@ public void sort(List insertions) { "This might indicate a circular entity relationship."); } insertions.clear(); - for (InsertInfo insertInfo : insertInfos) { - insertions.add(insertInfo.insertAction); + for ( InsertInfo insertInfo : insertInfos ) { + insertions.add( insertInfo.insertAction ); } } diff --git a/hibernate-core/src/main/java/org/hibernate/engine/spi/BatchFetchQueue.java b/hibernate-core/src/main/java/org/hibernate/engine/spi/BatchFetchQueue.java index 86fe23f1b96a..4b66722d8633 100644 --- a/hibernate-core/src/main/java/org/hibernate/engine/spi/BatchFetchQueue.java +++ b/hibernate-core/src/main/java/org/hibernate/engine/spi/BatchFetchQueue.java @@ -9,17 +9,13 @@ import java.util.Map; import org.hibernate.AssertionFailure; -import org.hibernate.cache.spi.access.CollectionDataAccess; -import org.hibernate.cache.spi.access.EntityDataAccess; import org.hibernate.collection.spi.PersistentCollection; import org.hibernate.internal.CoreLogging; import org.hibernate.internal.util.IndexedConsumer; -import org.hibernate.metamodel.mapping.EntityIdentifierMapping; import org.hibernate.metamodel.mapping.EntityMappingType; import org.hibernate.metamodel.mapping.PluralAttributeMapping; import org.hibernate.persister.collection.CollectionPersister; import org.hibernate.persister.entity.EntityPersister; -import org.hibernate.type.Type; import org.jboss.logging.Logger; @@ -98,10 +94,7 @@ public void clear() { * this entity key. */ public @Nullable SubselectFetch getSubselect(EntityKey key) { - if ( subselectsByEntityKey == null ) { - return null; - } - return subselectsByEntityKey.get( key ); + return subselectsByEntityKey == null ? null : subselectsByEntityKey.get( key ); } /** @@ -115,7 +108,7 @@ public void addSubselect(EntityKey key, SubselectFetch subquery) { subselectsByEntityKey = mapOfSize( 12 ); } - final SubselectFetch previous = subselectsByEntityKey.put( key, subquery ); + final var previous = subselectsByEntityKey.put( key, subquery ); if ( previous != null && LOG.isDebugEnabled() ) { LOG.debugf( "SubselectFetch previously registered with BatchFetchQueue for `%s#s`", @@ -168,9 +161,9 @@ public void addBatchLoadableEntityKey(EntityKey key) { public void removeBatchLoadableEntityKey(EntityKey key) { if ( key.isBatchLoadable( context.getSession().getLoadQueryInfluencers() ) && batchLoadableEntityKeys != null ) { - final LinkedHashSet set = batchLoadableEntityKeys.get( key.getEntityName() ); - if ( set != null ) { - set.remove( key ); + final var entityKeys = batchLoadableEntityKeys.get( key.getEntityName() ); + if ( entityKeys != null ) { + entityKeys.remove( key ); } } } @@ -181,9 +174,9 @@ public void removeBatchLoadableEntityKey(EntityKey key) { public boolean containsEntityKey(EntityKey key) { if ( key.isBatchLoadable( context.getSession().getLoadQueryInfluencers() ) && batchLoadableEntityKeys != null ) { - final LinkedHashSet set = batchLoadableEntityKeys.get( key.getEntityName() ); - if ( set != null ) { - return set.contains( key ); + final var entityKeys = batchLoadableEntityKeys.get( key.getEntityName() ); + if ( entityKeys != null ) { + return entityKeys.contains( key ); } } return false; @@ -203,39 +196,34 @@ public void collectBatchLoadableEntityIds( // make sure we load the id being loaded in the batch! collector.accept( 0, loadingId ); - if ( batchLoadableEntityKeys == null ) { - return; - } - - final LinkedHashSet set = batchLoadableEntityKeys.get( entityDescriptor.getEntityName() ); - if ( set == null ) { - return; - } - - final EntityIdentifierMapping identifierMapping = entityDescriptor.getIdentifierMapping(); - - int batchPosition = 1; - int end = -1; - boolean checkForEnd = false; - - for ( EntityKey key : set ) { - if ( checkForEnd && batchPosition == end ) { - // the first id found after the given id - return; - } - else if ( identifierMapping.areEqual( loadingId, key.getIdentifier(), context.getSession() ) ) { - end = batchPosition; - } - else if ( !isCached( key, entityDescriptor.getEntityPersister() ) ) { - //noinspection unchecked - collector.accept( batchPosition++, (T) key.getIdentifier() ); - } + if ( batchLoadableEntityKeys != null ) { + final var entityKeys = batchLoadableEntityKeys.get( entityDescriptor.getEntityName() ); + if ( entityKeys != null ) { + final var identifierMapping = entityDescriptor.getIdentifierMapping(); + int batchPosition = 1; + int end = -1; + boolean checkForEnd = false; + for ( var entityKey : entityKeys ) { + if ( checkForEnd && batchPosition == end ) { + // the first id found after the given id + return; + } + else if ( identifierMapping.areEqual( loadingId, entityKey.getIdentifier(), + context.getSession() ) ) { + end = batchPosition; + } + else if ( !isCached( entityKey, entityDescriptor.getEntityPersister() ) ) { + //noinspection unchecked + collector.accept( batchPosition++, (T) entityKey.getIdentifier() ); + } - if ( batchPosition == domainBatchSize ) { - // end of array, start filling again from start - batchPosition = 1; - if ( end != -1 ) { - checkForEnd = true; + if ( batchPosition == domainBatchSize ) { + // end of array, start filling again from start + batchPosition = 1; + if ( end != -1 ) { + checkForEnd = true; + } + } } } } @@ -255,43 +243,37 @@ else if ( !isCached( key, entityDescriptor.getEntityPersister() ) ) { // make sure we load the id being loaded in the batch! ids[0] = loadingId; - if ( batchLoadableEntityKeys == null ) { - return ids; - } - - int i = 1; - int end = -1; - boolean checkForEnd = false; - - // TODO: this needn't exclude subclasses... - - final LinkedHashSet set = - batchLoadableEntityKeys.get( entityDescriptor.getEntityName() ); - final EntityPersister entityPersister = entityDescriptor.getEntityPersister(); - final Type identifierType = entityPersister.getIdentifierType(); - if ( set != null ) { - for ( EntityKey key : set ) { - if ( checkForEnd && i == end ) { - // the first id found after the given id - return ids; - } - else if ( identifierType.isEqual( loadingId, key.getIdentifier() ) ) { - end = i; - } - else if ( !isCached( key, entityPersister ) ) { - ids[i++] = key.getIdentifier(); - } + if ( batchLoadableEntityKeys != null ) { + int i = 1; + int end = -1; + boolean checkForEnd = false; + // TODO: this needn't exclude subclasses... + final var entityKeys = batchLoadableEntityKeys.get( entityDescriptor.getEntityName() ); + if ( entityKeys != null ) { + final var entityPersister = entityDescriptor.getEntityPersister(); + final var identifierType = entityPersister.getIdentifierType(); + for ( var entityKey : entityKeys ) { + if ( checkForEnd && i == end ) { + // the first id found after the given id + return ids; + } + else if ( identifierType.isEqual( loadingId, entityKey.getIdentifier() ) ) { + end = i; + } + else if ( !isCached( entityKey, entityPersister ) ) { + ids[i++] = entityKey.getIdentifier(); + } - if ( i == maxBatchSize ) { - i = 1; // end of array, start filling again from start - if ( end != -1 ) { - checkForEnd = true; + if ( i == maxBatchSize ) { + i = 1; // end of array, start filling again from start + if ( end != -1 ) { + checkForEnd = true; + } } } } + //we ran out of ids to try } - - //we ran out of ids to try return ids; } @@ -303,7 +285,7 @@ else if ( !isCached( key, entityPersister ) ) { * it to the queue. */ public void addBatchLoadableCollection(PersistentCollection collection, CollectionEntry ce) { - final CollectionPersister persister = ce.getLoadedPersister(); + final var persister = ce.getLoadedPersister(); assert persister != null : "@AssumeAssertion(nullness)"; if ( batchLoadableCollections == null ) { batchLoadableCollections = mapOfSize( 12 ); @@ -318,7 +300,7 @@ public void addBatchLoadableCollection(PersistentCollection collection, Colle * if necessary */ public void removeBatchLoadableCollection(CollectionEntry ce) { - final CollectionPersister persister = ce.getLoadedPersister(); + final var persister = ce.getLoadedPersister(); assert persister != null : "@AssumeAssertion(nullness)"; if ( batchLoadableCollections != null ) { final var map = batchLoadableCollections.get( persister.getRole() ); @@ -332,7 +314,7 @@ public void removeBatchLoadableCollection(CollectionEntry ce) { /** * A "collector" form of {@link #getCollectionBatch}. * Useful in cases where we want a specially created array/container. - * Allows creation of concretely typed array for ARRAY param binding to + * Allows creation of a concretely typed array for ARRAY param binding to * ensure the driver does not need to cast or copy the values array. */ public void collectBatchLoadableCollectionKeys( @@ -342,62 +324,56 @@ public void collectBatchLoadableCollectionKeys( PluralAttributeMapping pluralAttributeMapping) { collector.accept( 0, keyBeingLoaded ); - if ( batchLoadableCollections == null ) { - return; - } - - final var map = batchLoadableCollections.get( pluralAttributeMapping.getNavigableRole().getFullPath() ); - if ( map == null ) { - return; - } - - int i = 1; - int end = -1; - boolean checkForEnd = false; - - for ( var me : map.entrySet() ) { - final CollectionEntry ce = me.getKey(); - final Object loadedKey = ce.getLoadedKey(); - final PersistentCollection collection = me.getValue(); - - // the loadedKey of the collectionEntry might be null as it might have been reset to null - // (see for example Collections.processDereferencedCollection() - // and CollectionEntry.afterAction()) - // though we clear the queue on flush, it seems like a good idea to guard - // against potentially null loadedKeys (which leads to various NPEs as demonstrated in HHH-7821). - - if ( loadedKey != null ) { - if ( collection.wasInitialized() ) { - throw new AssertionFailure( "Encountered initialized collection in BatchFetchQueue" ); - } - else if ( checkForEnd && i == end ) { - // the first key found after the given key - return; - } - else { - final boolean isEqual = - pluralAttributeMapping.getKeyDescriptor() - .areEqual( keyBeingLoaded, loadedKey, context.getSession() ); - if ( isEqual ) { - end = i; - } - else if ( !isCached( loadedKey, pluralAttributeMapping.getCollectionDescriptor() ) ) { - //noinspection unchecked - collector.accept( i++, (T) loadedKey ); - } + if ( batchLoadableCollections != null ) { + final var map = batchLoadableCollections.get( pluralAttributeMapping.getNavigableRole().getFullPath() ); + if ( map != null ) { + int i = 1; + int end = -1; + boolean checkForEnd = false; + for ( var me : map.entrySet() ) { + final CollectionEntry ce = me.getKey(); + final Object loadedKey = ce.getLoadedKey(); + final PersistentCollection collection = me.getValue(); + + // the loadedKey of the collectionEntry might be null as it might have been reset to null + // (see for example Collections.processDereferencedCollection() + // and CollectionEntry.afterAction()) + // though we clear the queue on flush, it seems like a good idea to guard + // against potentially null loadedKeys (which leads to various NPEs as demonstrated in HHH-7821). + + if ( loadedKey != null ) { + if ( collection.wasInitialized() ) { + throw new AssertionFailure( "Encountered initialized collection in BatchFetchQueue" ); + } + else if ( checkForEnd && i == end ) { + // the first key found after the given key + return; + } + else { + final boolean isEqual = + pluralAttributeMapping.getKeyDescriptor() + .areEqual( keyBeingLoaded, loadedKey, context.getSession() ); + if ( isEqual ) { + end = i; + } + else if ( !isCached( loadedKey, pluralAttributeMapping.getCollectionDescriptor() ) ) { + //noinspection unchecked + collector.accept( i++, (T) loadedKey ); + } - if ( i == batchSize ) { - //end of array, start filling again from start - i = 1; - if ( end != -1 ) { - checkForEnd = true; + if ( i == batchSize ) { + //end of array, start filling again from start + i = 1; + if ( end != -1 ) { + checkForEnd = true; + } + } } } } + //we ran out of keys to try } } - - //we ran out of keys to try } /** @@ -416,58 +392,57 @@ else if ( !isCached( loadedKey, pluralAttributeMapping.getCollectionDescriptor() final Object[] keys = new Object[batchSize]; keys[0] = id; - if ( batchLoadableCollections == null ) { - return keys; - } + if ( batchLoadableCollections != null ) { + int i = 1; + int end = -1; + boolean checkForEnd = false; - int i = 1; - int end = -1; - boolean checkForEnd = false; - - final var map = batchLoadableCollections.get( collectionPersister.getRole() ); - if ( map != null ) { - for ( var me : map.entrySet() ) { - final CollectionEntry ce = me.getKey(); - final Object loadedKey = ce.getLoadedKey(); - final PersistentCollection collection = me.getValue(); - - // the loadedKey of the collectionEntry might be null as it might have been reset to null - // (see for example Collections.processDereferencedCollection() - // and CollectionEntry.afterAction()) - // though we clear the queue on flush, it seems like a good idea to guard - // against potentially null loadedKeys (which leads to various NPEs as demonstrated in HHH-7821). - - if ( loadedKey != null ) { - if ( collection.wasInitialized() ) { - throw new AssertionFailure( "Encountered initialized collection in BatchFetchQueue" ); - } - else if ( checkForEnd && i == end ) { - return keys; //the first key found after the given key - } - else { - final boolean isEqual = - collectionPersister.getKeyType() - .isEqual( id, loadedKey, collectionPersister.getFactory() ); - if ( isEqual ) { - end = i; - //checkForEnd = false; + final var map = batchLoadableCollections.get( collectionPersister.getRole() ); + if ( map != null ) { + for ( var me : map.entrySet() ) { + final CollectionEntry ce = me.getKey(); + final Object loadedKey = ce.getLoadedKey(); + final PersistentCollection collection = me.getValue(); + + // the loadedKey of the collectionEntry might be null as it might have been reset to null + // (see for example Collections.processDereferencedCollection() + // and CollectionEntry.afterAction()) + // though we clear the queue on flush, it seems like a good idea to guard + // against potentially null loadedKeys (which leads to various NPEs as demonstrated in HHH-7821). + + if ( loadedKey != null ) { + if ( collection.wasInitialized() ) { + throw new AssertionFailure( "Encountered initialized collection in BatchFetchQueue" ); } - else if ( !isCached( loadedKey, collectionPersister ) ) { - keys[i++] = loadedKey; - //count++; + else if ( checkForEnd && i == end ) { + return keys; //the first key found after the given key } + else { + final boolean isEqual = + collectionPersister.getKeyType() + .isEqual( id, loadedKey, collectionPersister.getFactory() ); + if ( isEqual ) { + end = i; + //checkForEnd = false; + } + else if ( !isCached( loadedKey, collectionPersister ) ) { + keys[i++] = loadedKey; + //count++; + } - if ( i == batchSize ) { - i = 1; //end of array, start filling again from start - if ( end != -1 ) { - checkForEnd = true; + if ( i == batchSize ) { + i = 1; //end of array, start filling again from start + if ( end != -1 ) { + checkForEnd = true; + } } } } } } + //we ran out of keys to try } - return keys; //we ran out of keys to try + return keys; } public SharedSessionContractImplementor getSession() { @@ -475,9 +450,9 @@ public SharedSessionContractImplementor getSession() { } private boolean isCached(Object collectionKey, CollectionPersister persister) { - final SharedSessionContractImplementor session = getSession(); + final var session = getSession(); if ( session.getCacheMode().isGetEnabled() && persister.hasCache() ) { - final CollectionDataAccess cache = persister.getCacheAccessStrategy(); + final var cache = persister.getCacheAccessStrategy(); final Object cacheKey = cache.generateCacheKey( collectionKey, persister, session.getFactory(), session.getTenantIdentifier() ); @@ -489,9 +464,9 @@ private boolean isCached(Object collectionKey, CollectionPersister persister) { } private boolean isCached(EntityKey entityKey, EntityPersister persister) { - final SharedSessionContractImplementor session = getSession(); + final var session = getSession(); if ( session.getCacheMode().isGetEnabled() && persister.canReadFromCache() ) { - final EntityDataAccess cache = persister.getCacheAccessStrategy(); + final var cache = persister.getCacheAccessStrategy(); final Object key = cache.generateCacheKey( entityKey.getIdentifier(), persister, session.getFactory(), session.getTenantIdentifier() ); diff --git a/hibernate-core/src/main/java/org/hibernate/engine/spi/CacheInitiator.java b/hibernate-core/src/main/java/org/hibernate/engine/spi/CacheInitiator.java index 5c39441d4169..6a71dc2c506c 100644 --- a/hibernate-core/src/main/java/org/hibernate/engine/spi/CacheInitiator.java +++ b/hibernate-core/src/main/java/org/hibernate/engine/spi/CacheInitiator.java @@ -23,7 +23,7 @@ public class CacheInitiator implements SessionFactoryServiceInitiator graph, @Nullable GraphSemantic se if ( semantic == null ) { throw new IllegalArgumentException( "Graph semantic cannot be null" ); } - verifyWriteability(); - log.tracef( "Setting effective graph state [%s] : %s", semantic.name(), graph ); - this.semantic = semantic; this.graph = graph; } @@ -107,36 +104,34 @@ private void verifyWriteability() { * @throws IllegalStateException If previous state is still available (hasn't been cleared). */ public void applyConfiguredGraph(@Nullable Map properties) { - if ( properties == null || properties.isEmpty() ) { - return; - } - - var fetchHint = (RootGraphImplementor) properties.get( GraphSemantic.FETCH.getJpaHintName() ); - var loadHint = (RootGraphImplementor) properties.get( GraphSemantic.LOAD.getJpaHintName() ); - if ( fetchHint == null ) { - fetchHint = (RootGraphImplementor) properties.get( GraphSemantic.FETCH.getJakartaHintName() ); - } - if ( loadHint == null ) { - loadHint = (RootGraphImplementor) properties.get( GraphSemantic.LOAD.getJakartaHintName() ); - } + if ( properties != null && !properties.isEmpty() ) { + var fetchHint = (RootGraphImplementor) properties.get( GraphSemantic.FETCH.getJpaHintName() ); + var loadHint = (RootGraphImplementor) properties.get( GraphSemantic.LOAD.getJpaHintName() ); + if ( fetchHint == null ) { + fetchHint = (RootGraphImplementor) properties.get( GraphSemantic.FETCH.getJakartaHintName() ); + } + if ( loadHint == null ) { + loadHint = (RootGraphImplementor) properties.get( GraphSemantic.LOAD.getJakartaHintName() ); + } - if ( fetchHint != null ) { - if ( loadHint != null ) { - // can't have both - throw new IllegalArgumentException( - "Passed properties contained both a LOAD and a FETCH graph which is illegal - " + - "only one should be passed" - ); + if ( fetchHint != null ) { + if ( loadHint != null ) { + // can't have both + throw new IllegalArgumentException( + "Passed properties contained both a LOAD and a FETCH graph which is illegal - " + + "only one should be passed" + ); + } + applyGraph( fetchHint, GraphSemantic.FETCH ); + } + else if ( loadHint != null ) { + applyGraph( loadHint, GraphSemantic.LOAD ); } - applyGraph( fetchHint, GraphSemantic.FETCH ); - } - else if ( loadHint != null ) { - applyGraph( loadHint, GraphSemantic.LOAD ); } } public void clear() { - this.semantic = null; - this.graph = null; + semantic = null; + graph = null; } } diff --git a/hibernate-core/src/main/java/org/hibernate/engine/spi/ExecutableList.java b/hibernate-core/src/main/java/org/hibernate/engine/spi/ExecutableList.java index d7d70ef05250..497382b92cd1 100644 --- a/hibernate-core/src/main/java/org/hibernate/engine/spi/ExecutableList.java +++ b/hibernate-core/src/main/java/org/hibernate/engine/spi/ExecutableList.java @@ -18,10 +18,15 @@ import org.hibernate.action.spi.Executable; import org.hibernate.event.spi.EventSource; -import org.hibernate.internal.util.collections.CollectionHelper; import org.checkerframework.checker.nullness.qual.Nullable; +import static java.util.Collections.addAll; +import static java.util.Collections.emptySet; +import static java.util.Collections.unmodifiableList; +import static org.hibernate.internal.util.collections.CollectionHelper.isNotEmpty; +import static org.hibernate.internal.util.collections.CollectionHelper.setOfSize; + /** * A list of {@link Executable executeble actions}. Responsible for * {@linkplain #sort() sorting} the executables, and calculating the @@ -119,17 +124,17 @@ public ExecutableList(int initialCapacity, Sorter sorter) { */ public Set getQuerySpaces() { if ( querySpaces == null ) { - for ( ComparableExecutable e : executables ) { - Serializable[] propertySpaces = e.getPropertySpaces(); + for ( var executable : executables ) { + final var propertySpaces = executable.getPropertySpaces(); if ( propertySpaces != null && propertySpaces.length > 0 ) { if( querySpaces == null ) { querySpaces = new HashSet<>(); } - Collections.addAll( querySpaces, propertySpaces ); + addAll( querySpaces, propertySpaces ); } } if ( querySpaces == null ) { - return Collections.emptySet(); + return emptySet(); } } return querySpaces; @@ -150,20 +155,18 @@ public boolean isEmpty() { * @return the entry that was removed */ public ComparableExecutable remove(int index) { - // removals are generally safe with regard to sorting... - - final ComparableExecutable e = executables.remove( index ); - - // If the executable being removed defined query spaces we need to recalculate the overall query spaces for - // this list. The problem is that we don't know how many other executable instances in the list also - // contributed those query spaces as well. + // removals are generally safe with regard to sorting + final var executable = executables.remove( index ); + // If the executable being removed defined query spaces we need to recalculate the overall + // query spaces for this list. The problem is that we don't know how many other executable + // instances in the list also contributed those query spaces as well. // - // An alternative here is to use a "multiset" which is a specialized set that keeps a reference count - // associated to each entry. But that is likely overkill here. - if ( e.getPropertySpaces() != null && e.getPropertySpaces().length > 0 ) { + // An alternative here is to use a "multiset" which is a specialized set that keeps a + // reference count associated with each entry. But that is likely overkill here. + if ( isNotEmpty( executable.getPropertySpaces() ) ) { querySpaces = null; } - return e; + return executable; } /** @@ -182,9 +185,10 @@ public void clear() { */ public void removeLastN(int n) { if ( n > 0 ) { - int size = executables.size(); - for ( ComparableExecutable e : executables.subList( size - n, size ) ) { - if ( e.getPropertySpaces() != null && e.getPropertySpaces().length > 0 ) { + final int size = executables.size(); + for ( var executable : executables.subList( size - n, size ) ) { + final var propertySpaces = executable.getPropertySpaces(); + if ( isNotEmpty( propertySpaces ) ) { // querySpaces could now be incorrect querySpaces = null; break; @@ -202,34 +206,37 @@ public void removeLastN(int n) { * @return true if the object was added to the list */ public boolean add(E executable) { - final ComparableExecutable previousLast = sorter != null || executables.isEmpty() ? null : executables.get( executables.size() - 1 ); - boolean added = executables.add( executable ); - + final var previousLast = + sorter != null || executables.isEmpty() + ? null + : executables.get( executables.size() - 1 ); + final boolean added = executables.add( executable ); if ( !added ) { return false; } - - // if it was sorted before the addition, then check if the addition invalidated the sorting - if ( sorted ) { - if ( sorter != null ) { - // we don't have intrinsic insight into the sorter's algorithm, so invalidate sorting - sorted = false; - } - else { - // otherwise, we added to the end of the list. So check the comparison between the incoming - // executable and the one previously at the end of the list using the Comparable contract - if ( previousLast != null && previousLast.compareTo( executable ) > 0 ) { + else { + // if it was sorted before the addition, then check if the addition invalidated the sorting + if ( sorted ) { + if ( sorter != null ) { + // we don't have intrinsic insight into the sorter's algorithm, so invalidate sorting sorted = false; } + else { + // otherwise, we added to the end of the list. So check the comparison between the incoming + // executable and the one previously at the end of the list using the Comparable contract + if ( previousLast != null && previousLast.compareTo( executable ) > 0 ) { + sorted = false; + } + } } - } - Serializable[] querySpaces = executable.getPropertySpaces(); - if ( this.querySpaces != null && querySpaces != null ) { - Collections.addAll( this.querySpaces, querySpaces ); - } + final var addedQuerySpaces = executable.getPropertySpaces(); + if ( querySpaces != null && addedQuerySpaces != null ) { + addAll( querySpaces, addedQuerySpaces ); + } - return true; + return true; + } } /** @@ -272,7 +279,7 @@ public E get(int index) { */ @Override public Iterator iterator() { - return Collections.unmodifiableList( executables ).iterator(); + return unmodifiableList( executables ).iterator(); } /** @@ -294,10 +301,10 @@ public void writeExternal(ObjectOutput oos) throws IOException { oos.writeInt( -1 ); } else { - final Set qs = querySpaces; + final Set spaces = querySpaces; oos.writeInt( querySpaces.size() ); // these are always String, why we treat them as Serializable instead is beyond me... - for ( Serializable querySpace : qs ) { + for ( var querySpace : spaces ) { oos.writeUTF( querySpace.toString() ); } } @@ -329,7 +336,7 @@ public void readExternal(ObjectInput in) throws IOException, ClassNotFoundExcept } else { // The line below is for CF nullness checking purposes. - final Set querySpaces = CollectionHelper.setOfSize( numberOfQuerySpaces ); + final Set querySpaces = setOfSize( numberOfQuerySpaces ); for ( int i = 0; i < numberOfQuerySpaces; i++ ) { querySpaces.add( in.readUTF() ); } @@ -344,13 +351,12 @@ public void readExternal(ObjectInput in) throws IOException, ClassNotFoundExcept * @param session The session with which to associate the {@code Executable}s */ public void afterDeserialize(EventSource session) { - for ( ComparableExecutable e : executables ) { - e.afterDeserialize( session ); + for ( var executable : executables ) { + executable.afterDeserialize( session ); } } public String toString() { return "ExecutableList{size=" + executables.size() + "}"; } - } diff --git a/hibernate-core/src/main/java/org/hibernate/engine/spi/LoadQueryInfluencers.java b/hibernate-core/src/main/java/org/hibernate/engine/spi/LoadQueryInfluencers.java index cd495ccde8c5..349cdab58f4d 100644 --- a/hibernate-core/src/main/java/org/hibernate/engine/spi/LoadQueryInfluencers.java +++ b/hibernate-core/src/main/java/org/hibernate/engine/spi/LoadQueryInfluencers.java @@ -325,10 +325,9 @@ public boolean effectiveSubselectFetchEnabled(CollectionPersister persister) { private boolean isSubselectFetchEnabledInProfile(CollectionPersister persister) { if ( hasEnabledFetchProfiles() ) { + final var sqlTranslationEngine = persister.getFactory().getSqlTranslationEngine(); for ( String profile : getEnabledFetchProfileNames() ) { - final FetchProfile fetchProfile = - persister.getFactory().getSqlTranslationEngine() - .getFetchProfile( profile ) ; + final FetchProfile fetchProfile = sqlTranslationEngine.getFetchProfile( profile ) ; if ( fetchProfile != null ) { final Fetch fetch = fetchProfile.getFetchByRole( persister.getRole() ); if ( fetch != null && fetch.getMethod() == SUBSELECT) { @@ -348,8 +347,9 @@ public boolean hasSubselectLoadableCollections(EntityPersister persister) { private boolean hasSubselectLoadableCollectionsEnabledInProfile(EntityPersister persister) { if ( hasEnabledFetchProfiles() ) { + final var sqlTranslationEngine = persister.getFactory().getSqlTranslationEngine(); for ( String profile : getEnabledFetchProfileNames() ) { - if ( persister.getFactory().getSqlTranslationEngine().getFetchProfile( profile ) + if ( sqlTranslationEngine.getFetchProfile( profile ) .hasSubselectLoadableCollectionsEnabled( persister ) ) { return true; } diff --git a/hibernate-core/src/main/java/org/hibernate/internal/util/collections/ArrayHelper.java b/hibernate-core/src/main/java/org/hibernate/internal/util/collections/ArrayHelper.java index 9f180986af32..0a1dda1ad38a 100644 --- a/hibernate-core/src/main/java/org/hibernate/internal/util/collections/ArrayHelper.java +++ b/hibernate-core/src/main/java/org/hibernate/internal/util/collections/ArrayHelper.java @@ -4,23 +4,20 @@ */ package org.hibernate.internal.util.collections; -import java.io.Serializable; import java.lang.reflect.Array; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; -import java.util.Iterator; import java.util.List; -import java.util.SortedSet; -import java.util.TreeSet; import java.util.function.Consumer; -import org.hibernate.HibernateException; -import org.hibernate.LockMode; -import org.hibernate.LockOptions; import org.hibernate.internal.build.AllowReflection; import org.hibernate.type.Type; +import static java.lang.reflect.Array.get; +import static java.lang.reflect.Array.getLength; +import static java.util.Arrays.asList; + public final class ArrayHelper { public static boolean contains(T[] array, T object) { @@ -37,12 +34,12 @@ public static boolean containsAll(T[] array, T[] elements) { } public static boolean contains(int[] array, int value) { + //noinspection ForLoopReplaceableByForEach for ( int i = 0; i < array.length; i++ ) { if ( array[i] == value ) { return true; } } - return false; } @@ -76,30 +73,6 @@ public static String[] toStringArray(Object[] objects) { return result; } - public static String[] fillArray(String value, int length) { - String[] result = new String[length]; - Arrays.fill( result, value ); - return result; - } - - public static int[] fillArray(int value, int length) { - int[] result = new int[length]; - Arrays.fill( result, value ); - return result; - } - - public static LockMode[] fillArray(LockMode lockMode, int length) { - LockMode[] array = new LockMode[length]; - Arrays.fill( array, lockMode ); - return array; - } - - public static LockOptions[] fillArray(LockOptions lockOptions, int length) { - LockOptions[] array = new LockOptions[length]; - Arrays.fill( array, lockOptions ); - return array; - } - public static String[] toStringArray(Collection coll) { return coll.toArray( EMPTY_STRING_ARRAY ); } @@ -121,8 +94,8 @@ public static Type[] toTypeArray(Collection coll) { } public static int[] toIntArray(Collection coll) { - Iterator iter = coll.iterator(); - int[] arr = new int[coll.size()]; + final var iter = coll.iterator(); + final int[] arr = new int[coll.size()]; int i = 0; while ( iter.hasNext() ) { arr[i++] = iter.next(); @@ -131,8 +104,8 @@ public static int[] toIntArray(Collection coll) { } public static boolean[] toBooleanArray(Collection coll) { - Iterator iter = coll.iterator(); - boolean[] arr = new boolean[coll.size()]; + final var iter = coll.iterator(); + final boolean[] arr = new boolean[coll.size()]; int i = 0; while ( iter.hasNext() ) { arr[i++] = iter.next(); @@ -140,52 +113,27 @@ public static boolean[] toBooleanArray(Collection coll) { return arr; } - public static Object[] typecast(Object[] array, Object[] to) { - return Arrays.asList( array ).toArray( to ); - } - - //Arrays.asList doesn't do primitive arrays -// public static List toList(Object array) { -// if ( array instanceof Object[] ) { -// return Arrays.asList( (Object[]) array ); //faster? -// } -// int size = Array.getLength( array ); -// ArrayList list = new ArrayList<>( size ); -// for ( int i = 0; i < size; i++ ) { -// list.add( Array.get( array, i ) ); -// } -// return list; -// } - public static String[] slice(String[] strings, int begin, int length) { - String[] result = new String[length]; + final var result = new String[length]; System.arraycopy( strings, begin, result, 0, length ); return result; } public static Object[] slice(Object[] objects, int begin, int length) { - Object[] result = new Object[length]; + final var result = new Object[length]; System.arraycopy( objects, begin, result, 0, length ); return result; } - public static List toList(Iterator iter) { - List list = new ArrayList<>(); - while ( iter.hasNext() ) { - list.add( iter.next() ); - } - return list; - } - public static String[] join(String[] x, String[] y) { - String[] result = new String[x.length + y.length]; + final var result = new String[x.length + y.length]; System.arraycopy( x, 0, result, 0, x.length ); System.arraycopy( y, 0, result, x.length, y.length ); return result; } public static String[] join(String[] x, String[] y, boolean[] use) { - String[] result = new String[x.length + countTrue( use )]; + final var result = new String[x.length + countTrue( use )]; System.arraycopy( x, 0, result, 0, x.length ); int k = x.length; for ( int i = 0; i < y.length; i++ ) { @@ -197,7 +145,7 @@ public static String[] join(String[] x, String[] y, boolean[] use) { } public static int[] join(int[] x, int[] y) { - int[] result = new int[x.length + y.length]; + final var result = new int[x.length + y.length]; System.arraycopy( x, 0, result, 0, x.length ); System.arraycopy( y, 0, result, x.length, y.length ); return result; @@ -206,7 +154,7 @@ public static int[] join(int[] x, int[] y) { @SuppressWarnings("unchecked") @AllowReflection public static T[] join(T[] x, T... y) { - T[] result = (T[]) Array.newInstance( x.getClass().getComponentType(), x.length + y.length ); + final T[] result = (T[]) Array.newInstance( x.getClass().getComponentType(), x.length + y.length ); System.arraycopy( x, 0, result, 0, x.length ); System.arraycopy( y, 0, result, x.length, y.length ); return result; @@ -215,7 +163,7 @@ public static T[] join(T[] x, T... y) { @SuppressWarnings("unchecked") @AllowReflection public static T[] add(T[] x, T y) { - T[] result = (T[]) Array.newInstance( x.getClass().getComponentType(), x.length + 1 ); + final T[] result = (T[]) Array.newInstance( x.getClass().getComponentType(), x.length + 1 ); System.arraycopy( x, 0, result, 0, x.length ); result[x.length] = y; return result; @@ -228,21 +176,21 @@ private ArrayHelper() { } public static String toString(Object[] array) { - StringBuilder sb = new StringBuilder(); - sb.append( "[" ); + final var string = new StringBuilder(); + string.append( "[" ); for ( int i = 0; i < array.length; i++ ) { - sb.append( array[i] ); + string.append( array[i] ); if ( i < array.length - 1 ) { - sb.append( "," ); + string.append( "," ); } } - sb.append( "]" ); - return sb.toString(); + string.append( "]" ); + return string.toString(); } public static boolean isAllNegative(int[] array) { - for ( int anArray : array ) { - if ( anArray >= 0 ) { + for ( int element : array ) { + if ( element >= 0 ) { return false; } } @@ -250,8 +198,8 @@ public static boolean isAllNegative(int[] array) { } public static boolean isAllTrue(boolean... array) { - for ( boolean anArray : array ) { - if ( !anArray ) { + for ( boolean element : array ) { + if ( !element ) { return false; } } @@ -260,8 +208,8 @@ public static boolean isAllTrue(boolean... array) { public static int countTrue(boolean... array) { int result = 0; - for ( boolean anArray : array ) { - if ( anArray ) { + for ( boolean element : array ) { + if ( element ) { result++; } } @@ -269,8 +217,8 @@ public static int countTrue(boolean... array) { } public static boolean isAllFalse(boolean... array) { - for ( boolean anArray : array ) { - if ( anArray ) { + for ( boolean element : array ) { + if ( element ) { return false; } } @@ -287,7 +235,7 @@ public static boolean isAnyTrue(boolean... values) { } public static boolean[] negate(boolean[] valueNullness) { - boolean[] result = new boolean[valueNullness.length]; + final var result = new boolean[valueNullness.length]; for (int i = 0; i < valueNullness.length; i++) { result[i] = !valueNullness[i]; } @@ -296,152 +244,17 @@ public static boolean[] negate(boolean[] valueNullness) { public static void addAll(Collection collection, T[] array) { - collection.addAll( Arrays.asList( array ) ); + collection.addAll( asList( array ) ); } public static final String[] EMPTY_STRING_ARRAY = {}; public static final int[] EMPTY_INT_ARRAY = {}; public static final boolean[] EMPTY_BOOLEAN_ARRAY = {}; - public static final Class[] EMPTY_CLASS_ARRAY = {}; + public static final Class[] EMPTY_CLASS_ARRAY = {}; public static final Object[] EMPTY_OBJECT_ARRAY = {}; public static final Type[] EMPTY_TYPE_ARRAY = {}; public static final byte[] EMPTY_BYTE_ARRAY = {}; - /** - * Calculate the batch partitions needed to handle the {@code mappedBatchSize}. - * - * @param mappedBatchSize The {@link org.hibernate.annotations.BatchSize batch-size}. Internally - * this is capped at {@code 256} - * - * @implNote The max batch size is capped at {@code 256} - * - * @return The upper bound for the partitions - */ - public static int[] calculateBatchPartitions(int mappedBatchSize) { - final SortedSet partitionSizes = new TreeSet<>( Integer::compareTo ); - int batchSize = Math.min( mappedBatchSize, 256 ); - while ( batchSize > 1 ) { - partitionSizes.add( batchSize ); - batchSize = calculateNextBatchPartitionLimit( batchSize ); - } - - return ArrayHelper.toIntArray( partitionSizes ); - } - - private static int calculateNextBatchPartitionLimit(int batchSize) { - if ( batchSize <= 10 ) { - return batchSize - 1; //allow 9,8,7,6,5,4,3,2,1 - } - else if ( batchSize / 2 < 10 ) { - return 10; - } - else { - return batchSize / 2; - } - } - - public static int[] getBatchSizes(int maxBatchSize) { - int batchSize = maxBatchSize; - int n = 1; - while ( batchSize > 1 ) { - batchSize = getNextBatchSize( batchSize ); - n++; - } - int[] result = new int[n]; - batchSize = maxBatchSize; - for ( int i = 0; i < n; i++ ) { - result[i] = batchSize; - batchSize = getNextBatchSize( batchSize ); - } - return result; - } - - private static int getNextBatchSize(int batchSize) { - if ( batchSize <= 10 ) { - return batchSize - 1; //allow 9,8,7,6,5,4,3,2,1 - } - else if ( batchSize / 2 < 10 ) { - return 10; - } - else { - return batchSize / 2; - } - } - - private static final int SEED = 23; - private static final int PRIME_NUMBER = 37; - - /** - * calculate the array hash (only the first level) - */ - public static int hash(Object[] array) { - int seed = SEED; - for ( Object anArray : array ) { - seed = hash( seed, anArray == null ? 0 : anArray.hashCode() ); - } - return seed; - } - - /** - * calculate the array hash (only the first level) - */ - public static int hash(char[] array) { - int seed = SEED; - for ( char anArray : array ) { - seed = hash( seed, anArray ); - } - return seed; - } - - /** - * calculate the array hash (only the first level) - */ - public static int hash(byte[] bytes) { - int seed = SEED; - for ( byte aByte : bytes ) { - seed = hash( seed, aByte ); - } - return seed; - } - - private static int hash(int seed, int i) { - return PRIME_NUMBER * seed + i; - } - - public static Serializable[] extractNonNull(Serializable[] array) { - final int nonNullCount = countNonNull( array ); - final Serializable[] result = new Serializable[nonNullCount]; - int i = 0; - for ( Serializable element : array ) { - if ( element != null ) { - result[i++] = element; - } - } - if ( i != nonNullCount ) { - throw new HibernateException( "Number of non-null elements varied between iterations" ); - } - return result; - } - - public static int countNonNull(Serializable[] array) { - int i = 0; - for ( Serializable element : array ) { - if ( element != null ) { - i++; - } - } - return i; - } - - public static int countNonNull(Object[] array) { - int i = 0; - for ( Object element : array ) { - if ( element != null ) { - i++; - } - } - return i; - } /** * Reverse the elements of the incoming array @@ -450,7 +263,7 @@ public static int countNonNull(Object[] array) { */ public static String[] reverse(String[] source) { final int length = source.length; - final String[] destination = new String[length]; + final var destination = new String[length]; for ( int i = 0; i < length; i++ ) { destination[length - i - 1] = source[i]; } @@ -464,7 +277,7 @@ public static String[] reverse(String[] source) { */ public static String[] reverseFirst(String[] objects, int n) { final int length = objects.length; - final String[] destination = new String[length]; + final var destination = new String[length]; for ( int i = 0; i < n; i++ ) { destination[i] = objects[n - i - 1]; } @@ -481,7 +294,7 @@ public static String[] reverseFirst(String[] objects, int n) { */ public static String[][] reverseFirst(String[][] objects, int n) { final int length = objects.length; - final String[][] destination = new String[length][]; + final var destination = new String[length][]; for ( int i = 0; i < n; i++ ) { destination[i] = objects[n - i - 1]; } @@ -492,7 +305,7 @@ public static String[][] reverseFirst(String[][] objects, int n) { } public static int[] trim(int[] from, int length) { - int[] trimmed = new int[length]; + final var trimmed = new int[length]; System.arraycopy( from, 0, trimmed, 0, length ); return trimmed; } @@ -501,33 +314,34 @@ public static Object[] toObjectArray(Object array) { if ( array instanceof Object[] objects ) { return objects; } - final int arrayLength = Array.getLength( array ); - final Object[] outputArray = new Object[ arrayLength ]; - for ( int i = 0; i < arrayLength; ++i ) { - outputArray[ i ] = Array.get( array, i ); + else { + final int arrayLength = getLength( array ); + final var result = new Object[arrayLength]; + for ( int i = 0; i < arrayLength; ++i ) { + result[i] = get( array, i ); + } + return result; } - return outputArray; } public static List toExpandableList(T[] values) { - if ( values == null ) { - return new ArrayList<>(); - } - return Arrays.asList( values ); + return values == null ? new ArrayList<>() : asList( values ); } public static boolean isEmpty(Object[] array) { return array == null || array.length == 0; } - public static void forEach(T[] array, Consumer consumer) { - if ( array == null ) { - return; - } + public static int size(T[] array) { + return array == null ? 0 : array.length; + } - //noinspection ForLoopReplaceableByForEach - for ( int i = 0; i < array.length; i++ ) { - consumer.accept( array[ i ] ); + public static void forEach(T[] array, Consumer consumer) { + if ( array != null ) { + //noinspection ForLoopReplaceableByForEach + for ( int i = 0; i < array.length; i++ ) { + consumer.accept( array[i] ); + } } } @@ -540,8 +354,4 @@ public static void forEach(T[] array, Consumer consumer) { public static T[] newInstance(Class elementType, int length) { return (T[]) Array.newInstance( elementType, length ); } - - public static int size(T[] array) { - return array == null ? 0 : array.length; - } } diff --git a/hibernate-core/src/main/java/org/hibernate/internal/util/collections/CollectionHelper.java b/hibernate-core/src/main/java/org/hibernate/internal/util/collections/CollectionHelper.java index 2a7e50bb2805..6ecdf66c2541 100644 --- a/hibernate-core/src/main/java/org/hibernate/internal/util/collections/CollectionHelper.java +++ b/hibernate-core/src/main/java/org/hibernate/internal/util/collections/CollectionHelper.java @@ -8,7 +8,6 @@ import java.util.ArrayList; import java.util.Collection; -import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.LinkedHashMap; @@ -21,6 +20,7 @@ import java.util.function.Function; import static java.util.Arrays.asList; +import static java.util.Collections.addAll; import static java.util.Collections.emptyList; import static java.util.Collections.emptyMap; import static java.util.Collections.emptySet; @@ -290,15 +290,17 @@ public static List listOf(T value1) { return list; } + @SafeVarargs public static List listOf(T... values) { final List list = new ArrayList<>( values.length ); - Collections.addAll( list, values ); + addAll( list, values ); return list; } + @SafeVarargs public static Set setOf(T... values) { final HashSet set = new HashSet<>( determineProperSizing( values.length ) ); - Collections.addAll( set, values ); + addAll( set, values ); return set; }