diff --git a/build.gradle b/build.gradle index e9ca27a56..ee1cba98c 100644 --- a/build.gradle +++ b/build.gradle @@ -73,7 +73,7 @@ subprojects { ext.publishScript = rootProject.rootDir.absolutePath + '/publish.gradle' - tasks.withType( JavaCompile ) { + tasks.withType( JavaCompile ).configureEach { options.encoding = 'UTF-8' } diff --git a/gradle.properties b/gradle.properties index 911e9d9c4..660b06173 100644 --- a/gradle.properties +++ b/gradle.properties @@ -29,13 +29,13 @@ org.gradle.java.installations.auto-download=false #db = MSSQL # Enable the SonatypeOS maven repository (mainly for Vert.x snapshots) when present (value ignored) -#enableSonatypeOpenSourceSnapshotsRep = true +enableSonatypeOpenSourceSnapshotsRep = true # Enable the maven local repository (for local development when needed) when present (value ignored) #enableMavenLocalRepo = true # The default Hibernate ORM version (override using `-PhibernateOrmVersion=the.version.you.want`) -hibernateOrmVersion = 7.0.0.Beta3 +hibernateOrmVersion = 7.0.0-SNAPSHOT # Override default Hibernate ORM Gradle plugin version # Using the stable version because I don't know how to configure the build to download the snapshot version from @@ -44,7 +44,7 @@ hibernateOrmGradlePluginVersion = 7.0.0.Beta2 # If set to true, skip Hibernate ORM version parsing (default is true, if set to null) # this is required when using intervals or weird versions or the build will fail -#skipOrmVersionParsing = true +skipOrmVersionParsing = true # Override default Vert.x Sql client version #vertxSqlClientVersion = 4.5.12-SNAPSHOT diff --git a/hibernate-reactive-core/src/main/java/org/hibernate/engine/internal/ReactivePersistenceContextAdapter.java b/hibernate-reactive-core/src/main/java/org/hibernate/engine/internal/ReactivePersistenceContextAdapter.java new file mode 100644 index 000000000..6d189c3ef --- /dev/null +++ b/hibernate-reactive-core/src/main/java/org/hibernate/engine/internal/ReactivePersistenceContextAdapter.java @@ -0,0 +1,791 @@ +/* Hibernate, Relational Persistence for Idiomatic Java + * + * SPDX-License-Identifier: Apache-2.0 + * Copyright: Red Hat Inc. and Hibernate Authors + */ +package org.hibernate.engine.internal; + +import java.io.Serializable; +import java.util.Iterator; +import java.util.Map; +import java.util.concurrent.CompletionStage; +import java.util.function.BiConsumer; +import java.util.function.Consumer; +import java.util.function.Supplier; + +import org.hibernate.HibernateException; +import org.hibernate.Internal; +import org.hibernate.LockMode; +import org.hibernate.collection.spi.PersistentCollection; +import org.hibernate.engine.spi.BatchFetchQueue; +import org.hibernate.engine.spi.CollectionEntry; +import org.hibernate.engine.spi.CollectionKey; +import org.hibernate.engine.spi.EntityEntry; +import org.hibernate.engine.spi.EntityHolder; +import org.hibernate.engine.spi.EntityKey; +import org.hibernate.engine.spi.EntityUniqueKey; +import org.hibernate.engine.spi.NaturalIdResolutions; +import org.hibernate.engine.spi.PersistenceContext; +import org.hibernate.engine.spi.PersistentAttributeInterceptable; +import org.hibernate.engine.spi.SessionImplementor; +import org.hibernate.engine.spi.SharedSessionContractImplementor; +import org.hibernate.engine.spi.Status; +import org.hibernate.event.service.spi.EventListenerGroup; +import org.hibernate.event.spi.PostLoadEvent; +import org.hibernate.event.spi.PostLoadEventListener; +import org.hibernate.persister.collection.CollectionPersister; +import org.hibernate.persister.entity.EntityPersister; +import org.hibernate.reactive.engine.impl.ReactiveCallbackImpl; +import org.hibernate.reactive.logging.impl.Log; +import org.hibernate.reactive.persister.entity.impl.ReactiveEntityPersister; +import org.hibernate.reactive.session.ReactiveSession; +import org.hibernate.sql.exec.spi.Callback; +import org.hibernate.sql.results.graph.entity.EntityInitializer; +import org.hibernate.sql.results.jdbc.spi.JdbcValuesSourceProcessingState; +import org.hibernate.sql.results.spi.LoadContexts; + +import static java.lang.invoke.MethodHandles.lookup; +import static org.hibernate.reactive.logging.impl.LoggerFactory.make; +import static org.hibernate.reactive.util.impl.CompletionStages.completedFuture; +import static org.hibernate.reactive.util.impl.CompletionStages.loop; +import static org.hibernate.reactive.util.impl.CompletionStages.voidFuture; + +/** + * Add reactive methods to a {@link PersistenceContext}. + */ +public class ReactivePersistenceContextAdapter implements PersistenceContext { + + private static final Log LOG = make( Log.class, lookup() ); + + private final PersistenceContext delegate; + + /** + * Constructs a PersistentContext, bound to the given session. + */ + public ReactivePersistenceContextAdapter(PersistenceContext persistenceContext) { + this.delegate = persistenceContext; + } + + public CompletionStage reactiveInitializeNonLazyCollections() throws HibernateException { + final NonLazyCollectionInitializer initializer = new NonLazyCollectionInitializer(); + delegate.initializeNonLazyCollections( initializer ); + return initializer.stage; + } + + private class NonLazyCollectionInitializer implements Consumer> { + CompletionStage stage = voidFuture(); + + @Override + public void accept(PersistentCollection nonLazyCollection) { + if ( !nonLazyCollection.wasInitialized() ) { + stage = stage.thenCompose( v -> ( (ReactiveSession) getSession() ) + .reactiveInitializeCollection( nonLazyCollection, false ) ); + } + } + } + + /** + * @deprecated use {@link #reactiveInitializeNonLazyCollections} instead. + */ + @Deprecated + @Override + public void initializeNonLazyCollections() { + // still called by ResultSetProcessorImpl, so can't throw UnsupportedOperationException + } + + @Override + public void initializeNonLazyCollections(Consumer> initializeAction) { + throw LOG.nonReactiveMethodCall( "reactiveInitializeNonLazyCollection" ); + } + + @Deprecated + @Override + public Object[] getDatabaseSnapshot(Object id, EntityPersister persister) throws HibernateException { + throw LOG.nonReactiveMethodCall( "reactiveGetDatabaseSnapshot" ); + } + + private static final Object[] NO_ROW = new Object[] {StatefulPersistenceContext.NO_ROW}; + + public CompletionStage reactiveGetDatabaseSnapshot(Object id, EntityPersister persister) throws HibernateException { + SessionImplementor session = (SessionImplementor) getSession(); + final EntityKey key = session.generateEntityKey( id, persister ); + final Object[] cached = getEntitySnapshotsByKey() == null + ? null + : (Object[]) getEntitySnapshotsByKey().get( key ); + if ( cached != null ) { + return completedFuture( cached == NO_ROW ? null : cached ); + } + else { + return ( (ReactiveEntityPersister) persister ) + .reactiveGetDatabaseSnapshot( id, session ) + .thenApply( snapshot -> { + getOrInitializeEntitySnapshotsByKey().put( key, snapshot ); + return snapshot; + } ); + } + } + + @Override + public boolean isStateless() { + return delegate.isStateless(); + } + + @Override + public SharedSessionContractImplementor getSession() { + return delegate.getSession(); + } + + @Override + public LoadContexts getLoadContexts() { + return delegate.getLoadContexts(); + } + + @Override + public boolean hasLoadContext() { + return delegate.hasLoadContext(); + } + + @Override + public PersistentCollection useUnownedCollection(CollectionKey key) { + return delegate.useUnownedCollection( key ); + } + + @Override + public BatchFetchQueue getBatchFetchQueue() { + return delegate.getBatchFetchQueue(); + } + + @Override + public void clear() { + delegate.clear(); + } + + @Override + public void setEntryStatus(EntityEntry entry, Status status) { + delegate.setEntryStatus( entry, status ); + } + + @Override + public void afterTransactionCompletion() { + delegate.afterTransactionCompletion(); + } + + @Override + public Object[] getCachedDatabaseSnapshot(EntityKey key) { + return delegate.getCachedDatabaseSnapshot( key ); + } + + @Override + public Object getNaturalIdSnapshot(Object id, EntityPersister persister) { + return delegate.getNaturalIdSnapshot( id, persister ); + } + + @Override + public void addEntity(EntityKey key, Object entity) { + delegate.addEntity( key, entity ); + } + + @Override + public Object getEntity(EntityKey key) { + return delegate.getEntity( key ); + } + + @Override + public boolean containsEntity(EntityKey key) { + return delegate.containsEntity( key ); + } + + @Override + public Object removeEntity(EntityKey key) { + return delegate.removeEntity( key ); + } + + @Override + public void addEntity(EntityUniqueKey euk, Object entity) { + delegate.addEntity( euk, entity ); + } + + @Override + public Object getEntity(EntityUniqueKey euk) { + return delegate.getEntity( euk ); + } + + @Override + public EntityEntry getEntry(Object entity) { + return delegate.getEntry( entity ); + } + + @Override + public EntityEntry removeEntry(Object entity) { + return delegate.removeEntry( entity ); + } + + @Override + public boolean isEntryFor(Object entity) { + return delegate.isEntryFor( entity ); + } + + @Override + public CollectionEntry getCollectionEntry(PersistentCollection coll) { + return delegate.getCollectionEntry( coll ); + } + + @Override + public EntityEntry addEntity( + Object entity, + Status status, + Object[] loadedState, + EntityKey entityKey, + Object version, + LockMode lockMode, + boolean existsInDatabase, + EntityPersister persister, + boolean disableVersionIncrement) { + return delegate.addEntity( + entity, + status, + loadedState, + entityKey, + version, + lockMode, + existsInDatabase, + persister, + disableVersionIncrement + ); + } + + @Override + public EntityEntry addEntry( + Object entity, + Status status, + Object[] loadedState, + Object rowId, + Object id, + Object version, + LockMode lockMode, + boolean existsInDatabase, + EntityPersister persister, + boolean disableVersionIncrement) { + return delegate.addEntry( + entity, + status, + loadedState, + rowId, + id, + version, + lockMode, + existsInDatabase, + persister, + disableVersionIncrement + ); + } + + @Override + public EntityEntry addReferenceEntry(Object entity, Status status) { + return delegate.addReferenceEntry( entity, status ); + } + + @Override + public boolean containsCollection(PersistentCollection collection) { + return delegate.containsCollection( collection ); + } + + @Override + public boolean containsProxy(Object proxy) { + return delegate.containsProxy( proxy ); + } + + @Override + public boolean reassociateIfUninitializedProxy(Object value) { + return delegate.reassociateIfUninitializedProxy( value ); + } + + @Override + public void reassociateProxy(Object value, Object id) { + delegate.reassociateProxy( value, id ); + } + + @Override + public Object unproxy(Object maybeProxy) { + return delegate.unproxy( maybeProxy ); + } + + @Override + public Object unproxyAndReassociate(Object maybeProxy) { + return delegate.unproxyAndReassociate( maybeProxy ); + } + + @Override + public void checkUniqueness(EntityKey key, Object object) { + delegate.checkUniqueness( key, object ); + } + + @Override + public Object narrowProxy(Object proxy, EntityPersister persister, EntityKey key, Object object) { + return delegate.narrowProxy( proxy, persister, key, object ); + } + + @Override + public Object proxyFor(EntityPersister persister, EntityKey key, Object impl) { + return delegate.proxyFor( persister, key, impl ); + } + + @Override + public Object proxyFor(Object impl) { + return delegate.proxyFor( impl ); + } + + @Override + public Object proxyFor(EntityHolder holder, EntityPersister persister) { + return delegate.proxyFor( holder, persister ); + } + + @Override + public void addEnhancedProxy(EntityKey key, PersistentAttributeInterceptable entity) { + delegate.addEnhancedProxy( key, entity ); + } + + @Override + public Object getCollectionOwner(Object key, CollectionPersister collectionPersister) { + return delegate.getCollectionOwner( key, collectionPersister ); + } + + @Override + public Object getLoadedCollectionOwnerOrNull(PersistentCollection collection) { + return delegate.getLoadedCollectionOwnerOrNull( collection ); + } + + @Override + public Object getLoadedCollectionOwnerIdOrNull(PersistentCollection collection) { + return delegate.getLoadedCollectionOwnerIdOrNull( collection ); + } + + @Override + public void addUninitializedCollection(CollectionPersister persister, PersistentCollection collection, Object id) { + delegate.addUninitializedCollection( persister, collection, id ); + } + + @Override + public void addUninitializedDetachedCollection(CollectionPersister persister, PersistentCollection collection) { + delegate.addUninitializedDetachedCollection( persister, collection ); + } + + @Override + public void addNewCollection(CollectionPersister persister, PersistentCollection collection) { + delegate.addNewCollection( persister, collection ); + } + + @Override + public void addInitializedDetachedCollection(CollectionPersister collectionPersister, PersistentCollection collection) { + delegate.addInitializedDetachedCollection( collectionPersister, collection ); + } + + @Override + public void replaceCollection(CollectionPersister persister, PersistentCollection oldCollection, PersistentCollection collection) { + delegate.replaceCollection( persister, oldCollection, collection ); + } + + @Override + public CollectionEntry addInitializedCollection(CollectionPersister persister, PersistentCollection collection, Object id) { + return delegate.addInitializedCollection( persister, collection, id ); + } + + @Override + public PersistentCollection getCollection(CollectionKey collectionKey) { + return delegate.getCollection( collectionKey ); + } + + @Override + public void addNonLazyCollection(PersistentCollection collection) { + delegate.addNonLazyCollection( collection ); + } + + @Override + public PersistentCollection getCollectionHolder(Object array) { + return delegate.getCollectionHolder( array ); + } + + @Override + public void addCollectionHolder(PersistentCollection holder) { + delegate.addCollectionHolder( holder ); + } + + @Override + public PersistentCollection removeCollectionHolder(Object array) { + return delegate.removeCollectionHolder( array ); + } + + @Override + public Serializable getSnapshot(PersistentCollection coll) { + return delegate.getSnapshot( coll ); + } + + @Override + public Object getProxy(EntityKey key) { + return delegate.getProxy( key ); + } + + @Override + public void addProxy(EntityKey key, Object proxy) { + delegate.addProxy( key, proxy ); + } + + @Override + public Object removeProxy(EntityKey key) { + return delegate.removeProxy( key ); + } + + @Override + public EntityHolder claimEntityHolderIfPossible(EntityKey key, Object entity, JdbcValuesSourceProcessingState processingState, EntityInitializer initializer) { + return delegate.claimEntityHolderIfPossible( key, entity, processingState, initializer ); + } + + @Override + public EntityHolder addEntityHolder(EntityKey key, Object entity) { + return delegate.addEntityHolder( key, entity ); + } + + @Override + public EntityHolder getEntityHolder(EntityKey key) { + return delegate.getEntityHolder( key ); + } + + @Override + public boolean containsEntityHolder(EntityKey key) { + return delegate.containsEntityHolder( key ); + } + + @Override + public EntityHolder removeEntityHolder(EntityKey key) { + return delegate.removeEntityHolder( key ); + } + + @Override + public void postLoad(JdbcValuesSourceProcessingState processingState, Consumer loadedConsumer) { + throw LOG.nonReactiveMethodCall( "reactivePostLoad(JdbcValuesSourceProcessingState, Consumer) )" ); + } + + @Internal + @Override + public Map getEntitiesByKey() { + return delegate.getEntitiesByKey(); + } + + @Internal + @Override + public Map getEntityHoldersByKey() { + return delegate.getEntityHoldersByKey(); + } + + @Override + public Map.Entry[] reentrantSafeEntityEntries() { + return delegate.reentrantSafeEntityEntries(); + } + + @Override + public int getNumberOfManagedEntities() { + return delegate.getNumberOfManagedEntities(); + } + + @Internal + @Override + public Map, CollectionEntry> getCollectionEntries() { + return delegate.getCollectionEntries(); + } + + @Override + public void forEachCollectionEntry(BiConsumer, CollectionEntry> action, boolean concurrent) { + delegate.forEachCollectionEntry( action, concurrent ); + } + + @Deprecated + @Override + public Map> getCollectionsByKey() { + return delegate.getCollectionsByKey(); + } + + @Override + public int getCascadeLevel() { + return delegate.getCascadeLevel(); + } + + @Override + public int incrementCascadeLevel() { + return delegate.incrementCascadeLevel(); + } + + @Override + public int decrementCascadeLevel() { + return delegate.decrementCascadeLevel(); + } + + @Override + public boolean isFlushing() { + return delegate.isFlushing(); + } + + @Override + public void setFlushing(boolean flushing) { + delegate.setFlushing( flushing ); + } + + @Override + public void beforeLoad() { + delegate.beforeLoad(); + } + + @Override + public void afterLoad() { + delegate.afterLoad(); + } + + @Override + public boolean isLoadFinished() { + return delegate.isLoadFinished(); + } + + @Override + public String toString() { + return delegate.toString(); + } + + @Override + public Object getOwnerId(String entityName, String propertyName, Object childEntity, Map mergeMap) { + return delegate.getOwnerId( entityName, propertyName, childEntity, mergeMap ); + } + + @Override + public Object getIndexInOwner(String entity, String property, Object childObject, Map mergeMap) { + return delegate.getIndexInOwner( entity, property, childObject, mergeMap ); + } + + @Override + public void addNullProperty(EntityKey ownerKey, String propertyName) { + delegate.addNullProperty( ownerKey, propertyName ); + } + + @Override + public boolean isPropertyNull(EntityKey ownerKey, String propertyName) { + return delegate.isPropertyNull( ownerKey, propertyName ); + } + + @Override + public boolean isDefaultReadOnly() { + return delegate.isDefaultReadOnly(); + } + + @Override + public void setDefaultReadOnly(boolean readOnly) { + delegate.setDefaultReadOnly( readOnly ); + } + + @Override + public boolean isReadOnly(Object entityOrProxy) { + return delegate.isReadOnly( entityOrProxy ); + } + + @Override + public void setReadOnly(Object entityOrProxy, boolean readOnly) { + delegate.setReadOnly( entityOrProxy, readOnly ); + } + + @Override + public boolean isRemovingOrphanBeforeUpdates() { + return delegate.isRemovingOrphanBeforeUpdates(); + } + + @Override + public void beginRemoveOrphanBeforeUpdates() { + delegate.beginRemoveOrphanBeforeUpdates(); + } + + @Override + public void endRemoveOrphanBeforeUpdates() { + delegate.endRemoveOrphanBeforeUpdates(); + } + + @Override + public void replaceDelayedEntityIdentityInsertKeys(EntityKey oldKey, Object generatedId) { + delegate.replaceDelayedEntityIdentityInsertKeys( oldKey, generatedId ); + } + + @Internal + @Override + public void replaceEntityEntryRowId(Object entity, Object rowId) { + delegate.replaceEntityEntryRowId( entity, rowId ); + } + + @Override + public void addChildParent(Object child, Object parent) { + delegate.addChildParent( child, parent ); + } + + @Override + public void removeChildParent(Object child) { + delegate.removeChildParent( child ); + } + + @Override + public void registerInsertedKey(EntityPersister persister, Object id) { + delegate.registerInsertedKey( persister, id ); + } + + @Override + public boolean wasInsertedDuringTransaction(EntityPersister persister, Object id) { + return delegate.wasInsertedDuringTransaction( persister, id ); + } + + @Override + public boolean containsNullifiableEntityKey(Supplier sek) { + return delegate.containsNullifiableEntityKey( sek ); + } + + @Override + public void registerNullifiableEntityKey(EntityKey key) { + delegate.registerNullifiableEntityKey( key ); + } + + @Override + public boolean isNullifiableEntityKeysEmpty() { + return delegate.isNullifiableEntityKeysEmpty(); + } + + @Override + public boolean containsDeletedUnloadedEntityKey(EntityKey ek) { + return delegate.containsDeletedUnloadedEntityKey( ek ); + } + + @Override + public void registerDeletedUnloadedEntityKey(EntityKey key) { + delegate.registerDeletedUnloadedEntityKey( key ); + } + + @Override + public void removeDeletedUnloadedEntityKey(EntityKey key) { + delegate.removeDeletedUnloadedEntityKey( key ); + } + + @Override + public boolean containsDeletedUnloadedEntityKeys() { + return delegate.containsDeletedUnloadedEntityKeys(); + } + + @Override + public int getCollectionEntriesSize() { + return delegate.getCollectionEntriesSize(); + } + + @Override + public CollectionEntry removeCollectionEntry(PersistentCollection collection) { + return delegate.removeCollectionEntry( collection ); + } + + @Override + public void clearCollectionsByKey() { + delegate.clearCollectionsByKey(); + } + + @Override + public PersistentCollection addCollectionByKey(CollectionKey collectionKey, PersistentCollection persistentCollection) { + return delegate.addCollectionByKey( collectionKey, persistentCollection ); + } + + @Override + public void removeCollectionByKey(CollectionKey collectionKey) { + delegate.removeCollectionByKey( collectionKey ); + } + + @Internal + @Override + public Map getEntitySnapshotsByKey() { + return delegate.getEntitySnapshotsByKey(); + } + + @Override + @Internal + public Map getOrInitializeEntitySnapshotsByKey() { + return delegate.getOrInitializeEntitySnapshotsByKey(); + } + + @Override + public Iterator managedEntitiesIterator() { + return delegate.managedEntitiesIterator(); + } + + @Override + public NaturalIdResolutions getNaturalIdResolutions() { + return delegate.getNaturalIdResolutions(); + } + + /** + * Reactive version of {@link StatefulPersistenceContext#postLoad(JdbcValuesSourceProcessingState, Consumer)} + * + */ + public CompletionStage reactivePostLoad(JdbcValuesSourceProcessingState processingState, Consumer holderConsumer) { + final ReactiveCallbackImpl callback = (ReactiveCallbackImpl) processingState.getExecutionContext().getCallback(); + + if ( processingState.getLoadingEntityHolders() != null ) { + final EventListenerGroup listenerGroup = + getSession().getFactory().getEventListenerGroups().eventListenerGroup_POST_LOAD; + final PostLoadEvent postLoadEvent = processingState.getPostLoadEvent(); + return loop( + processingState.getLoadingEntityHolders(), entityHolder -> + processLoadedEntityHolder( + entityHolder, + listenerGroup, + postLoadEvent, + callback, + holderConsumer + )) + .thenAccept( v -> processingState.getLoadingEntityHolders().clear() ); + } + if ( processingState.getReloadedEntityHolders() != null ) { + return loop( + processingState.getLoadingEntityHolders(), entityHolder -> + processLoadedEntityHolder( + entityHolder, + null, + null, + callback, + holderConsumer + )) + .thenAccept( v -> processingState.getLoadingEntityHolders().clear() ); + } + return voidFuture(); + } + + /** + * Reactive version of {@link StatefulPersistenceContext#processLoadedEntityHolder(EntityHolder, EventListenerGroup, PostLoadEvent, Callback, Consumer)} + */ + private CompletionStage processLoadedEntityHolder( + EntityHolder holder, + EventListenerGroup listenerGroup, + PostLoadEvent postLoadEvent, + ReactiveCallbackImpl callback, + Consumer holderConsumer) { + if ( holderConsumer != null ) { + holderConsumer.accept( holder ); + } + if ( holder.getEntity() == null ) { + // It's possible that we tried to load an entity and found out it doesn't exist, + // in which case we added an entry with a null proxy and entity. + // Remove that empty entry on post load to avoid unwanted side effects + getEntitiesByKey().remove( holder.getEntityKey() ); + } + else { + if ( postLoadEvent != null ) { + postLoadEvent.reset(); + postLoadEvent.setEntity( holder.getEntity() ) + .setId( holder.getEntityKey().getIdentifier() ) + .setPersister( holder.getDescriptor() ); + listenerGroup.fireEventOnEachListener( postLoadEvent, PostLoadEventListener::onPostLoad ); + if ( callback != null ) { + return callback + .invokeReactiveLoadActions( holder.getEntity(), holder.getDescriptor(), getSession() ) + .thenAccept( v -> holder.resetEntityInitialier() ); + } + } + } + return voidFuture(); + } +} diff --git a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/engine/impl/Cascade.java b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/engine/impl/Cascade.java index 36466b556..a13426966 100644 --- a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/engine/impl/Cascade.java +++ b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/engine/impl/Cascade.java @@ -235,10 +235,7 @@ else if ( action.performOnLazyProperty() && type.isEntityType() ) { false ) ); } - else { - // Nothing to do, so just skip cascading to this lazy attribute. - continue; - } + // Nothing to do, so just skip cascading to this lazy attribute. } else { Object child = persister.getValue( parent, i ); @@ -447,7 +444,7 @@ private static CompletionStage cascadeLogicalOneToOneOrphanRemoval( * * @param type The type representing the attribute metadata * - * @return True if the attribute represents a logical one to one association + * @return True if the attribute represents a logical one-to-one association */ private static boolean isLogicalOneToOne(Type type) { return type.isEntityType() && ( (EntityType) type ).isLogicalOneToOne(); diff --git a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/engine/impl/EntityTypes.java b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/engine/impl/EntityTypes.java index fb1c29fe4..0bb0c75ae 100644 --- a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/engine/impl/EntityTypes.java +++ b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/engine/impl/EntityTypes.java @@ -76,8 +76,7 @@ public static CompletionStage resolve(EntityType entityType, Object idOr * @see OneToOneType#isNull(Object, SharedSessionContractImplementor) */ static boolean isNull(EntityType entityType, Object owner, SharedSessionContractImplementor session) { - if ( entityType instanceof OneToOneType ) { - OneToOneType type = (OneToOneType) entityType; + if ( entityType instanceof OneToOneType type ) { String propertyName = type.getPropertyName(); if ( propertyName != null ) { final EntityPersister ownerPersister = session.getFactory() @@ -126,7 +125,7 @@ static CompletionStage loadByUniqueKey( entityName, uniqueKeyPropertyName, key, - entityType.getIdentifierOrUniqueKeyType( factory ), + entityType.getIdentifierOrUniqueKeyType( factory.getRuntimeMetamodels() ), factory ); @@ -273,7 +272,7 @@ private static CompletionStage resolveIdOrUniqueKey( .reactiveFetch( id, true ) .thenCompose( fetched -> { Object idOrUniqueKey = entityType - .getIdentifierOrUniqueKeyType( session.getFactory() ) + .getIdentifierOrUniqueKeyType( session.getFactory().getRuntimeMetamodels() ) .replace( fetched, null, session, owner, copyCache ); if ( idOrUniqueKey instanceof CompletionStage ) { return ( (CompletionStage) idOrUniqueKey ) diff --git a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/engine/impl/ForeignKeys.java b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/engine/impl/ForeignKeys.java index 5a77bd9f6..087623e44 100644 --- a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/engine/impl/ForeignKeys.java +++ b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/engine/impl/ForeignKeys.java @@ -11,6 +11,7 @@ import org.hibernate.TransientObjectException; import org.hibernate.bytecode.enhance.spi.LazyPropertyInitializer; import org.hibernate.engine.internal.NonNullableTransientDependencies; +import org.hibernate.engine.internal.ReactivePersistenceContextAdapter; import org.hibernate.engine.spi.EntityEntry; import org.hibernate.engine.spi.PersistenceContext; import org.hibernate.engine.spi.SelfDirtinessTracker; diff --git a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/engine/impl/ReactiveCallbackImpl.java b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/engine/impl/ReactiveCallbackImpl.java new file mode 100644 index 000000000..609f021ba --- /dev/null +++ b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/engine/impl/ReactiveCallbackImpl.java @@ -0,0 +1,70 @@ +/* Hibernate, Relational Persistence for Idiomatic Java + * + * SPDX-License-Identifier: Apache-2.0 + * Copyright: Red Hat Inc. and Hibernate Authors + */ +package org.hibernate.reactive.engine.impl; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.CompletionStage; + +import org.hibernate.engine.spi.SharedSessionContractImplementor; +import org.hibernate.loader.ast.spi.AfterLoadAction; +import org.hibernate.metamodel.mapping.EntityMappingType; +import org.hibernate.reactive.loader.ast.spi.ReactiveAfterLoadAction; +import org.hibernate.reactive.logging.impl.Log; +import org.hibernate.sql.exec.spi.Callback; + +import static java.lang.invoke.MethodHandles.lookup; +import static org.hibernate.reactive.logging.impl.LoggerFactory.make; +import static org.hibernate.reactive.util.impl.CompletionStages.loop; + +/** + * Reactive equivalent of {@link org.hibernate.sql.exec.internal.CallbackImpl} + */ +public class ReactiveCallbackImpl implements Callback { + private static final Log LOG = make( Log.class, lookup() ); + + private final List afterLoadActions; + + public ReactiveCallbackImpl() { + this.afterLoadActions = new ArrayList<>( 1 ); + } + + @Override + public void registerAfterLoadAction(AfterLoadAction afterLoadAction) { + throw LOG.nonReactiveMethodCall( "registerReactiveAfterLoadAction(ReactiveCallbackImpl)" ); + } + + public void registerReactiveAfterLoadAction(ReactiveAfterLoadAction afterLoadAction) { + afterLoadActions.add( afterLoadAction ); + } + + @Override + public void invokeAfterLoadActions( + Object entity, + EntityMappingType entityMappingType, + SharedSessionContractImplementor session) { + throw LOG.nonReactiveMethodCall( "invokeAfterLoadActions(Object, EntityMappingType, SharedSessionContractImplementor)" ); + } + + /** + * Reactive version of {@link org.hibernate.sql.exec.internal.CallbackImpl#invokeAfterLoadActions(Object, EntityMappingType, SharedSessionContractImplementor)} + */ + public CompletionStage invokeReactiveLoadActions( + Object entity, + EntityMappingType entityMappingType, + SharedSessionContractImplementor session) { + return loop( + afterLoadActions, afterLoadAction -> + afterLoadAction.reactiveAfterLoad( entity, entityMappingType, session ) + ); + } + + @Override + public boolean hasAfterLoadActions() { + return !afterLoadActions.isEmpty(); + } + +} diff --git a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/engine/impl/ReactiveCollectionRecreateAction.java b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/engine/impl/ReactiveCollectionRecreateAction.java index 008755086..37f8eaa7e 100644 --- a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/engine/impl/ReactiveCollectionRecreateAction.java +++ b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/engine/impl/ReactiveCollectionRecreateAction.java @@ -56,7 +56,7 @@ public void execute() throws HibernateException { } private void preRecreate() { - getFastSessionServices() + getEventListenerGroups() .eventListenerGroup_PRE_COLLECTION_RECREATE .fireLazyEventOnEachListener( this::newPreCollectionRecreateEvent, PreCollectionRecreateEventListener::onPreRecreateCollection ); } @@ -66,7 +66,7 @@ private PreCollectionRecreateEvent newPreCollectionRecreateEvent() { } private void postRecreate() { - getFastSessionServices() + getEventListenerGroups() .eventListenerGroup_POST_COLLECTION_RECREATE .fireLazyEventOnEachListener( this::newPostCollectionRecreateEvent, PostCollectionRecreateEventListener::onPostRecreateCollection ); } diff --git a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/engine/impl/ReactiveCollectionRemoveAction.java b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/engine/impl/ReactiveCollectionRemoveAction.java index 4b086cf34..0f2bdefea 100644 --- a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/engine/impl/ReactiveCollectionRemoveAction.java +++ b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/engine/impl/ReactiveCollectionRemoveAction.java @@ -100,7 +100,8 @@ public void execute() throws HibernateException { } private void preRemove() { - getFastSessionServices().eventListenerGroup_PRE_COLLECTION_REMOVE + getEventListenerGroups() + .eventListenerGroup_PRE_COLLECTION_REMOVE .fireLazyEventOnEachListener( this::newPreCollectionRemoveEvent, PreCollectionRemoveEventListener::onPreRemoveCollection ); } @@ -115,7 +116,8 @@ private PreCollectionRemoveEvent newPreCollectionRemoveEvent() { } private void postRemove() { - getFastSessionServices().eventListenerGroup_POST_COLLECTION_REMOVE + getEventListenerGroups() + .eventListenerGroup_POST_COLLECTION_REMOVE .fireLazyEventOnEachListener( this::newPostCollectionRemoveEvent, PostCollectionRemoveEventListener::onPostRemoveCollection ); } diff --git a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/engine/impl/ReactiveCollectionUpdateAction.java b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/engine/impl/ReactiveCollectionUpdateAction.java index eae872d56..8806b3e9d 100644 --- a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/engine/impl/ReactiveCollectionUpdateAction.java +++ b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/engine/impl/ReactiveCollectionUpdateAction.java @@ -118,7 +118,8 @@ public void execute() throws HibernateException { } private void preUpdate() { - getFastSessionServices().eventListenerGroup_PRE_COLLECTION_UPDATE + getEventListenerGroups() + .eventListenerGroup_PRE_COLLECTION_UPDATE .fireLazyEventOnEachListener( this::newPreCollectionUpdateEvent, PreCollectionUpdateEventListener::onPreUpdateCollection ); } @@ -132,7 +133,8 @@ private PreCollectionUpdateEvent newPreCollectionUpdateEvent() { } private void postUpdate() { - getFastSessionServices().eventListenerGroup_POST_COLLECTION_UPDATE + getEventListenerGroups() + .eventListenerGroup_POST_COLLECTION_UPDATE .fireLazyEventOnEachListener( this::newPostCollectionUpdateEvent, PostCollectionUpdateEventListener::onPostUpdateCollection ); } diff --git a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/engine/impl/ReactivePersistenceContextAdapter.java b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/engine/impl/ReactivePersistenceContextAdapter.java deleted file mode 100644 index 33750cc0d..000000000 --- a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/engine/impl/ReactivePersistenceContextAdapter.java +++ /dev/null @@ -1,134 +0,0 @@ -/* Hibernate, Relational Persistence for Idiomatic Java - * - * SPDX-License-Identifier: Apache-2.0 - * Copyright: Red Hat Inc. and Hibernate Authors - */ -package org.hibernate.reactive.engine.impl; - -import java.io.Serializable; -import java.util.HashMap; -import java.util.concurrent.CompletionStage; -import java.util.function.Consumer; - -import org.hibernate.HibernateException; -import org.hibernate.collection.spi.PersistentCollection; -import org.hibernate.engine.internal.StatefulPersistenceContext; -import org.hibernate.engine.spi.EntityKey; -import org.hibernate.engine.spi.PersistenceContext; -import org.hibernate.engine.spi.SessionImplementor; -import org.hibernate.engine.spi.SharedSessionContractImplementor; -import org.hibernate.persister.entity.EntityPersister; -import org.hibernate.reactive.logging.impl.Log; -import org.hibernate.reactive.persister.entity.impl.ReactiveEntityPersister; -import org.hibernate.reactive.session.ReactiveSession; - -import static java.lang.invoke.MethodHandles.lookup; -import static org.hibernate.pretty.MessageHelper.infoString; -import static org.hibernate.reactive.logging.impl.LoggerFactory.make; -import static org.hibernate.reactive.util.impl.CompletionStages.completedFuture; -import static org.hibernate.reactive.util.impl.CompletionStages.voidFuture; - -/** - * Add reactive methods to a {@link PersistenceContext}. - */ -public class ReactivePersistenceContextAdapter extends StatefulPersistenceContext { - - private static final Log LOG = make( Log.class, lookup() ); - - private HashMap entitySnapshotsByKey; - - /** - * Constructs a PersistentContext, bound to the given session. - * - * @param session The session "owning" this context. - */ - public ReactivePersistenceContextAdapter(SharedSessionContractImplementor session) { - super( session ); - } - - public CompletionStage reactiveInitializeNonLazyCollections() throws HibernateException { - final NonLazyCollectionInitializer initializer = new NonLazyCollectionInitializer(); - initializeNonLazyCollections( initializer ); - return initializer.stage; - } - - private class NonLazyCollectionInitializer implements Consumer> { - CompletionStage stage = voidFuture(); - - @Override - public void accept(PersistentCollection nonLazyCollection) { - if ( !nonLazyCollection.wasInitialized() ) { - stage = stage.thenCompose( v -> ( (ReactiveSession) getSession() ) - .reactiveInitializeCollection( nonLazyCollection, false ) ); - } - } - } - - /** - * @deprecated use {@link #reactiveInitializeNonLazyCollections} instead. - */ - @Deprecated - @Override - public void initializeNonLazyCollections() { - // still called by ResultSetProcessorImpl, so can't throw UnsupportedOperationException - } - - @Deprecated - @Override - public Object[] getDatabaseSnapshot(Object id, EntityPersister persister) throws HibernateException { - throw LOG.nonReactiveMethodCall( "reactiveGetDatabaseSnapshot" ); - } - - private static final Object[] NO_ROW = new Object[]{ StatefulPersistenceContext.NO_ROW }; - - public CompletionStage reactiveGetDatabaseSnapshot(Object id, EntityPersister persister) - throws HibernateException { - - SessionImplementor session = (SessionImplementor) getSession(); - final EntityKey key = session.generateEntityKey( id, persister ); - final Object[] cached = entitySnapshotsByKey == null ? null : entitySnapshotsByKey.get( key ); - if ( cached != null ) { - return completedFuture( cached == NO_ROW ? null : cached ); - } - else { - return ( (ReactiveEntityPersister) persister ) - .reactiveGetDatabaseSnapshot( id, session ) - .thenApply( snapshot -> { - if ( entitySnapshotsByKey == null ) { - entitySnapshotsByKey = new HashMap<>( 8 ); - } - entitySnapshotsByKey.put( key, snapshot == null ? NO_ROW : snapshot ); - return snapshot; - } ); - } - } - - //All below methods copy/pasted from superclass because entitySnapshotsByKey is private: - - @Override - public Object[] getCachedDatabaseSnapshot(EntityKey key) { - final Object[] snapshot = entitySnapshotsByKey == null ? null : entitySnapshotsByKey.get( key ); - if ( snapshot == NO_ROW ) { - throw new IllegalStateException( - "persistence context reported no row snapshot for " - + infoString( key.getEntityName(), key.getIdentifier() ) - ); - } - return snapshot; - } - - @Override - public void clear() { - super.clear(); - entitySnapshotsByKey = null; - } - - @Override - public Object removeEntity(EntityKey key) { - Object result = super.removeEntity(key); - if (entitySnapshotsByKey != null ) { - entitySnapshotsByKey.remove(key); - } - return result; - } -} diff --git a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/event/ReactiveResolveNaturalIdEventListener.java b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/event/ReactiveResolveNaturalIdEventListener.java deleted file mode 100644 index fe0fbb96a..000000000 --- a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/event/ReactiveResolveNaturalIdEventListener.java +++ /dev/null @@ -1,29 +0,0 @@ -/* Hibernate, Relational Persistence for Idiomatic Java - * - * SPDX-License-Identifier: Apache-2.0 - * Copyright: Red Hat Inc. and Hibernate Authors - */ -package org.hibernate.reactive.event; - -import org.hibernate.event.spi.ResolveNaturalIdEvent; - -import java.util.concurrent.CompletionStage; - -/** - * Defines the contract for handling of resolve natural id events generated from a session. - * - * @author Eric Dalquist - * @author Steve Ebersole - * - * @see org.hibernate.event.spi.ResolveNaturalIdEventListener - */ -public interface ReactiveResolveNaturalIdEventListener { - - /** - * Handle the given resolve natural id event. - * - * @param event The resolve natural id event to be handled. - */ - CompletionStage onReactiveResolveNaturalId(ResolveNaturalIdEvent event); - -} diff --git a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/event/impl/AbstractReactiveFlushingEventListener.java b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/event/impl/AbstractReactiveFlushingEventListener.java index 2772cc15d..9e4ac049d 100644 --- a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/event/impl/AbstractReactiveFlushingEventListener.java +++ b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/event/impl/AbstractReactiveFlushingEventListener.java @@ -74,7 +74,7 @@ private ReactiveActionQueue actionQueue(EventSource session) { /** * Coordinates the processing necessary to get things ready for executions - * as db calls by preping the session caches and moving the appropriate + * as db calls by prepping the session caches and moving the appropriate * entities and collections to their respective execution queues. * * @param event The flush event. @@ -139,9 +139,8 @@ protected void logFlushResults(FlushEvent event) { session.getActionQueue().numberOfCollectionRemovals(), persistenceContext.getCollectionEntriesSize() ); - new EntityPrinter( session.getFactory() ).toString( - persistenceContext.getEntityHoldersByKey().entrySet() - ); + new EntityPrinter( session.getFactory() ) + .logEntities( persistenceContext.getEntityHoldersByKey().entrySet() ); } /** @@ -227,7 +226,7 @@ private int flushEntities(final FlushEvent event, final PersistenceContext persi final EventSource source = event.getSession(); final Iterable flushListeners = source.getFactory() - .getFastSessionServices() + .getEventListenerGroups() .eventListenerGroup_FLUSH_ENTITY .listeners(); diff --git a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/event/impl/DefaultReactiveDeleteEventListener.java b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/event/impl/DefaultReactiveDeleteEventListener.java index 66151f03b..664b09da3 100644 --- a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/event/impl/DefaultReactiveDeleteEventListener.java +++ b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/event/impl/DefaultReactiveDeleteEventListener.java @@ -13,7 +13,6 @@ import org.hibernate.TransientObjectException; import org.hibernate.bytecode.enhance.spi.LazyPropertyInitializer; import org.hibernate.bytecode.spi.BytecodeEnhancementMetadata; -import org.hibernate.classic.Lifecycle; import org.hibernate.engine.internal.CascadePoint; import org.hibernate.engine.internal.Nullability; import org.hibernate.engine.spi.EntityEntry; @@ -22,13 +21,13 @@ import org.hibernate.engine.spi.Status; import org.hibernate.event.internal.OnUpdateVisitor; import org.hibernate.event.internal.PostDeleteEventListenerStandardImpl; +import org.hibernate.event.service.spi.EventListenerGroups; import org.hibernate.event.service.spi.JpaBootstrapSensitive; import org.hibernate.event.spi.DeleteContext; import org.hibernate.event.spi.DeleteEvent; import org.hibernate.event.spi.DeleteEventListener; import org.hibernate.event.spi.EventSource; import org.hibernate.internal.EmptyInterceptor; -import org.hibernate.internal.FastSessionServices; import org.hibernate.jpa.event.spi.CallbackRegistry; import org.hibernate.jpa.event.spi.CallbackRegistryConsumer; import org.hibernate.jpa.event.spi.CallbackType; @@ -205,17 +204,6 @@ private CompletionStage fetchAndDelete(DeleteEvent event, DeleteContext tr } - protected boolean invokeDeleteLifecycle(EventSource session, Object entity, EntityPersister persister) { - if ( persister.implementsLifecycle() ) { - LOG.debug( "Calling onDelete()" ); - if ( ( (Lifecycle) entity ).onDelete( session ) ) { - LOG.debug( "Deletion vetoed by onDelete()" ); - return true; - } - } - return false; - } - private CompletionStage deleteTransientInstance(DeleteEvent event, DeleteContext transientEntities, Object entity) { LOG.trace( "Entity was not persistent in delete processing" ); @@ -291,23 +279,20 @@ private CompletionStage delete( Object version, EntityEntry entry) { callbackRegistry.preRemove( entity ); - if ( !invokeDeleteLifecycle( source, entity, persister ) ) { - return deleteEntity( - source, - entity, - entry, - event.isCascadeDeleteEnabled(), - event.isOrphanRemovalBeforeUpdates(), - persister, - transientEntities - ) - .thenAccept( v -> { - if ( source.getFactory().getSessionFactoryOptions().isIdentifierRollbackEnabled() ) { - persister.resetIdentifier( entity, id, version, source ); - } - } ); - } - return voidFuture(); + return deleteEntity( + source, + entity, + entry, + event.isCascadeDeleteEnabled(), + event.isOrphanRemovalBeforeUpdates(), + persister, + transientEntities + ) + .thenAccept( v -> { + if ( source.getFactory().getSessionFactoryOptions().isIdentifierRollbackEnabled() ) { + persister.resetIdentifier( entity, id, version, source ); + } + } ); } /** @@ -315,7 +300,6 @@ private CompletionStage delete( */ private boolean canBeDeletedWithoutLoading(EventSource source, EntityPersister persister) { return source.getInterceptor() == EmptyInterceptor.INSTANCE - && !persister.implementsLifecycle() && !persister.hasSubclasses() //TODO: should be unnecessary, using EntityPersister.getSubclassPropertyTypeClosure(), etc && !persister.hasCascadeDelete() && !persister.hasNaturalIdentifier() @@ -325,7 +309,7 @@ private boolean canBeDeletedWithoutLoading(EventSource source, EntityPersister p } private static boolean hasCustomEventListeners(EventSource source) { - final FastSessionServices fss = source.getFactory().getFastSessionServices(); + final EventListenerGroups fss = source.getFactory().getEventListenerGroups(); // Bean Validation adds a PRE_DELETE listener // and Envers adds a POST_DELETE listener return fss.eventListenerGroup_PRE_DELETE.count() > 0 diff --git a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/event/impl/DefaultReactiveLoadEventListener.java b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/event/impl/DefaultReactiveLoadEventListener.java index 8f821a986..9804a02f6 100644 --- a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/event/impl/DefaultReactiveLoadEventListener.java +++ b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/event/impl/DefaultReactiveLoadEventListener.java @@ -27,8 +27,7 @@ import org.hibernate.event.spi.EventSource; import org.hibernate.event.spi.LoadEvent; import org.hibernate.event.spi.LoadEventListener; -import org.hibernate.loader.ast.internal.CacheEntityLoaderHelper; -import org.hibernate.loader.ast.internal.CacheEntityLoaderHelper.PersistenceContextEntry; +import org.hibernate.loader.internal.CacheLoadHelper; import org.hibernate.metamodel.mapping.AttributeMapping; import org.hibernate.metamodel.mapping.AttributeMappingsList; import org.hibernate.metamodel.mapping.CompositeIdentifierMapping; @@ -40,7 +39,6 @@ import org.hibernate.proxy.HibernateProxy; import org.hibernate.proxy.LazyInitializer; import org.hibernate.reactive.event.ReactiveLoadEventListener; -import org.hibernate.reactive.loader.entity.ReactiveCacheEntityLoaderHelper; import org.hibernate.reactive.logging.impl.Log; import org.hibernate.reactive.logging.impl.LoggerFactory; import org.hibernate.reactive.persister.entity.impl.ReactiveEntityPersister; @@ -49,7 +47,10 @@ import static org.hibernate.engine.internal.ManagedTypeHelper.asPersistentAttributeInterceptable; import static org.hibernate.engine.internal.ManagedTypeHelper.isPersistentAttributeInterceptable; +import static org.hibernate.loader.internal.CacheLoadHelper.loadFromSecondLevelCache; +import static org.hibernate.loader.internal.CacheLoadHelper.loadFromSessionCache; import static org.hibernate.pretty.MessageHelper.infoString; +import static org.hibernate.proxy.HibernateProxy.extractLazyInitializer; import static org.hibernate.reactive.session.impl.SessionUtil.checkEntityFound; import static org.hibernate.reactive.session.impl.SessionUtil.throwEntityNotFound; import static org.hibernate.reactive.util.impl.CompletionStages.completedFuture; @@ -399,7 +400,7 @@ private static CompletionStage loadWithProxyFactory(LoadEvent event, Ent if ( proxy != null ) { LOG.trace( "Entity proxy found in session cache" ); - if ( LOG.isDebugEnabled() && HibernateProxy.extractLazyInitializer( proxy ).isUnwrap() ) { + if ( LOG.isDebugEnabled() && extractLazyInitializer( proxy ).isUnwrap() ) { LOG.debug( "Ignoring NO_PROXY to honor laziness" ); } @@ -429,7 +430,7 @@ private static PersistentAttributeInterceptable createBatchLoadableEnhancedProxy } private static Object proxyOrCached(LoadEvent event, EntityPersister persister, EntityKey keyToLoad) { - final Object cachedEntity = CacheEntityLoaderHelper.INSTANCE.loadFromSecondLevelCache( + final Object cachedEntity = loadFromSecondLevelCache( event.getSession(), null, LockMode.NONE, @@ -450,7 +451,7 @@ private static Object proxyOrCached(LoadEvent event, EntityPersister persister, return options.isCheckDeleted() && wasDeleted( persistenceContext, existing ) ? null : existing; } if ( persister.hasSubclasses() ) { - final Object cachedEntity = CacheEntityLoaderHelper.INSTANCE.loadFromSecondLevelCache( + final Object cachedEntity = loadFromSecondLevelCache( event.getSession(), null, LockMode.NONE, @@ -652,9 +653,9 @@ private CompletionStage doLoad( return nullFuture(); } else { - final PersistenceContextEntry persistenceContextEntry = - ReactiveCacheEntityLoaderHelper.INSTANCE.loadFromSessionCache( event, keyToLoad, options ); - final Object entity = persistenceContextEntry.getEntity(); + final CacheLoadHelper.PersistenceContextEntry persistenceContextEntry = + loadFromSessionCache( keyToLoad, event.getLockOptions(), options, event.getSession() ); + final Object entity = persistenceContextEntry.entity(); if ( entity != null ) { return persistenceContextEntry.isManaged() ? initializeIfNecessary( entity ) : nullFuture(); } @@ -668,9 +669,7 @@ private static CompletionStage initializeIfNecessary(Object entity) { if ( isPersistentAttributeInterceptable( entity ) ) { final PersistentAttributeInterceptable interceptable = asPersistentAttributeInterceptable( entity ); final PersistentAttributeInterceptor interceptor = interceptable.$$_hibernate_getInterceptor(); - if ( interceptor instanceof EnhancementAsProxyLazinessInterceptor) { - final EnhancementAsProxyLazinessInterceptor lazinessInterceptor = - (EnhancementAsProxyLazinessInterceptor) interceptor; + if ( interceptor instanceof EnhancementAsProxyLazinessInterceptor lazinessInterceptor ) { final SharedSessionContractImplementor session = lazinessInterceptor.getLinkedSession(); if ( session == null ) { throw LOG.sessionClosedLazyInitializationException(); @@ -691,7 +690,8 @@ private CompletionStage loadFromCacheOrDatasource( EntityPersister persister, EntityKey keyToLoad) { final EventSource session = event.getSession(); - final Object entity = CacheEntityLoaderHelper.INSTANCE.loadFromSecondLevelCache(event, persister, keyToLoad); + final Object entity = session + .loadFromSecondLevelCache( persister, keyToLoad, event.getInstanceToLoad(), event.getLockMode() ); if ( entity != null ) { if ( LOG.isTraceEnabled() ) { LOG.tracev( @@ -740,6 +740,10 @@ private void cacheNaturalId(LoadEvent event, EntityPersister persister, EventSou * @return The object loaded from the datasource, or null if not found. */ protected CompletionStage loadFromDatasource(LoadEvent event, EntityPersister persister) { + if ( LOG.isTraceEnabled() ) { + LOG.trace( "Entity not resolved in any cache, loading from datastore: " + + infoString( persister, event.getEntityId(), event.getFactory() ) ); + } return ( (ReactiveEntityPersister) persister ) .reactiveLoad( event.getEntityId(), @@ -754,16 +758,14 @@ protected CompletionStage loadFromDatasource(LoadEvent event, EntityPers // persister/loader/initializer sensitive to this fact - possibly // passing LoadType along - final LazyInitializer lazyInitializer = HibernateProxy.extractLazyInitializer( entity ); - if ( lazyInitializer != null ) { - entity = lazyInitializer.getImplementation(); - } + final LazyInitializer lazyInitializer = extractLazyInitializer( entity ); + final Object impl = lazyInitializer != null ? lazyInitializer.getImplementation() : entity; final StatisticsImplementor statistics = event.getSession().getFactory().getStatistics(); if ( event.isAssociationFetch() && statistics.isStatisticsEnabled() ) { statistics.fetchEntity( event.getEntityClassName() ); } - return entity; + return impl; } ); } } diff --git a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/event/impl/DefaultReactiveMergeEventListener.java b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/event/impl/DefaultReactiveMergeEventListener.java index 7f258a1d4..e6cc4cd95 100644 --- a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/event/impl/DefaultReactiveMergeEventListener.java +++ b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/event/impl/DefaultReactiveMergeEventListener.java @@ -94,7 +94,9 @@ protected Map getMergeMap(MergeContext context) { @Override public CompletionStage reactiveOnMerge(MergeEvent event) throws HibernateException { final EventSource session = event.getSession(); - final EntityCopyObserver entityCopyObserver = createEntityCopyObserver( session ); + final EntityCopyObserver entityCopyObserver = session.getFactory() + .getEntityCopyObserver() + .createEntityCopyObserver(); final MergeContext mergeContext = new MergeContext( session, entityCopyObserver ); return reactiveOnMerge( event, mergeContext ) .thenAccept( v -> entityCopyObserver.topLevelMergeComplete( session ) ) @@ -104,10 +106,6 @@ public CompletionStage reactiveOnMerge(MergeEvent event) throws HibernateE } ); } - private EntityCopyObserver createEntityCopyObserver(final EventSource session) { - return session.getFactory().getFastSessionServices().entityCopyObserverFactory.createEntityCopyObserver(); - } - /** * Handle the given merge event. * diff --git a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/event/impl/DefaultReactivePostLoadEventListener.java b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/event/impl/DefaultReactivePostLoadEventListener.java index 053c8465f..e1af57441 100644 --- a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/event/impl/DefaultReactivePostLoadEventListener.java +++ b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/event/impl/DefaultReactivePostLoadEventListener.java @@ -6,7 +6,6 @@ package org.hibernate.reactive.event.impl; import org.hibernate.AssertionFailure; -import org.hibernate.classic.Lifecycle; import org.hibernate.engine.spi.EntityEntry; import org.hibernate.event.spi.EventSource; import org.hibernate.event.spi.PostLoadEvent; @@ -21,7 +20,6 @@ /** * We do two things here: *
    - *
  • Call {@link Lifecycle} interface if necessary
  • *
  • Perform needed {@link EntityEntry#getLockMode()} related processing
  • *
* diff --git a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/event/impl/DefaultReactiveResolveNaturalIdEventListener.java b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/event/impl/DefaultReactiveResolveNaturalIdEventListener.java deleted file mode 100644 index 783c02ec8..000000000 --- a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/event/impl/DefaultReactiveResolveNaturalIdEventListener.java +++ /dev/null @@ -1,135 +0,0 @@ -/* Hibernate, Relational Persistence for Idiomatic Java - * - * SPDX-License-Identifier: Apache-2.0 - * Copyright: Red Hat Inc. and Hibernate Authors - */ -package org.hibernate.reactive.event.impl; - -import java.lang.invoke.MethodHandles; -import java.util.concurrent.CompletionStage; - -import org.hibernate.HibernateException; -import org.hibernate.engine.spi.NaturalIdResolutions; -import org.hibernate.event.spi.EventSource; -import org.hibernate.event.spi.ResolveNaturalIdEvent; -import org.hibernate.event.spi.ResolveNaturalIdEventListener; -import org.hibernate.persister.entity.EntityPersister; -import org.hibernate.reactive.event.ReactiveResolveNaturalIdEventListener; -import org.hibernate.reactive.logging.impl.Log; -import org.hibernate.reactive.logging.impl.LoggerFactory; -import org.hibernate.reactive.persister.entity.impl.ReactiveEntityPersister; -import org.hibernate.stat.spi.StatisticsImplementor; - -import static java.util.concurrent.TimeUnit.MILLISECONDS; -import static java.util.concurrent.TimeUnit.NANOSECONDS; -import static org.hibernate.pretty.MessageHelper.infoString; -import static org.hibernate.reactive.util.impl.CompletionStages.completedFuture; - -/** - * A reactive {@link org.hibernate.event.internal.DefaultResolveNaturalIdEventListener}. - */ -public class DefaultReactiveResolveNaturalIdEventListener implements ReactiveResolveNaturalIdEventListener, ResolveNaturalIdEventListener { - - private static final Log LOG = LoggerFactory.make( Log.class, MethodHandles.lookup() ); - - @Override - public void onResolveNaturalId(ResolveNaturalIdEvent event) throws HibernateException { - throw new UnsupportedOperationException(); - } - - @Override - public CompletionStage onReactiveResolveNaturalId(ResolveNaturalIdEvent event) throws HibernateException { - return resolveNaturalId( event ).thenAccept( event::setEntityId ); - } - - /** - * Coordinates the efforts to load a given entity. First, an attempt is - * made to load the entity from the session-level cache. If not found there, - * an attempt is made to locate it in second-level cache. Lastly, an - * attempt is made to load it directly from the datasource. - * - * @param event The load event - * - * @return The loaded entity, or null. - */ - protected CompletionStage resolveNaturalId(ResolveNaturalIdEvent event) { - final EntityPersister persister = event.getEntityPersister(); - - if ( LOG.isTraceEnabled() ) { - LOG.tracev( - "Attempting to resolve: {0}#{1}", - infoString( persister ), - event.getNaturalIdValues() - ); - } - - final Object entityId = resolveFromCache( event ); - if ( entityId != null ) { - if ( LOG.isTraceEnabled() ) { - LOG.tracev( - "Resolved object in cache: {0}#{1}", - infoString( persister ), - event.getNaturalIdValues() ); - } - return completedFuture( entityId ); - } - - if ( LOG.isTraceEnabled() ) { - LOG.tracev( - "Object not resolved in any cache: {0}#{1}", - infoString( persister ), - event.getNaturalIdValues() - ); - } - - return loadFromDatasource( event ); - } - - /** - * Attempts to resolve the entity id corresponding to the event's natural id values from the session - * - * @param event The load event - * @return The entity from the cache, or null. - */ - protected Object resolveFromCache(ResolveNaturalIdEvent event) { - return getNaturalIdResolutions( event ) - .findCachedIdByNaturalId( event.getOrderedNaturalIdValues(), event.getEntityPersister() ); - } - - /** - * Performs the process of loading an entity from the configured - * underlying datasource. - * - * @param event The load event - * - * @return The object loaded from the datasource, or null if not found. - */ - protected CompletionStage loadFromDatasource(ResolveNaturalIdEvent event) { - final EventSource session = event.getSession(); - final EntityPersister entityPersister = event.getEntityPersister(); - final StatisticsImplementor statistics = session.getFactory().getStatistics(); - final boolean statisticsEnabled = statistics.isStatisticsEnabled(); - final long startTime = statisticsEnabled ? System.nanoTime() : 0; - - return ( (ReactiveEntityPersister) entityPersister ) - .reactiveLoadEntityIdByNaturalId( event.getOrderedNaturalIdValues(), event.getLockOptions(), session ) - .thenApply( pk -> { - if ( statisticsEnabled ) { - long milliseconds = MILLISECONDS.convert( System.nanoTime() - startTime, NANOSECONDS ); - statistics.naturalIdQueryExecuted( entityPersister.getRootEntityName(), milliseconds ); - } - - //PK can be null if the entity doesn't exist - if ( pk != null ) { - getNaturalIdResolutions( event ) - .cacheResolutionFromLoad( pk, event.getOrderedNaturalIdValues(), entityPersister ); - } - - return pk; - } ); - } - - private static NaturalIdResolutions getNaturalIdResolutions(ResolveNaturalIdEvent event) { - return event.getSession().getPersistenceContextInternal().getNaturalIdResolutions(); - } -} diff --git a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/id/impl/BlockingIdentifierGenerator.java b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/id/impl/BlockingIdentifierGenerator.java index 224410853..c820f513f 100644 --- a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/id/impl/BlockingIdentifierGenerator.java +++ b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/id/impl/BlockingIdentifierGenerator.java @@ -5,19 +5,19 @@ */ package org.hibernate.reactive.id.impl; +import java.util.Objects; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.CompletionStage; + +import org.hibernate.reactive.id.ReactiveIdentifierGenerator; +import org.hibernate.reactive.session.ReactiveConnectionSupplier; + import io.vertx.core.Context; import io.vertx.core.Vertx; import io.vertx.core.net.impl.pool.CombinerExecutor; import io.vertx.core.net.impl.pool.Executor; import io.vertx.core.net.impl.pool.Task; -import org.hibernate.reactive.id.ReactiveIdentifierGenerator; -import org.hibernate.reactive.session.ReactiveConnectionSupplier; - -import java.util.Objects; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.CompletionStage; - import static org.hibernate.reactive.util.impl.CompletionStages.completedFuture; /** @@ -51,7 +51,7 @@ public abstract class BlockingIdentifierGenerator implements ReactiveIdentifierG */ protected abstract CompletionStage nextHiValue(ReactiveConnectionSupplier session); - //Not strictly necessary to put these fields into a dedicated class, but it help + //Not strictly necessary to put these fields into a dedicated class, but it helps //to reason about what the current state is and what the CombinerExecutor is //supposed to work on. private static class GeneratorState { @@ -138,7 +138,6 @@ public Task execute(GeneratorState state) { // value in the table, so just increment the lo // value and return the next id in the block completedFuture( local ).whenComplete( this::acceptAsReturnValue ); - return null; } else { nextHiValue( connectionSupplier ) @@ -155,8 +154,8 @@ public Task execute(GeneratorState state) { } ); } } ); - return null; } + return null; } private void acceptAsReturnValue(final Long aLong, final Throwable throwable) { diff --git a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/id/impl/EmulatedSequenceReactiveIdentifierGenerator.java b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/id/impl/EmulatedSequenceReactiveIdentifierGenerator.java index dd9702c69..b973c869b 100644 --- a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/id/impl/EmulatedSequenceReactiveIdentifierGenerator.java +++ b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/id/impl/EmulatedSequenceReactiveIdentifierGenerator.java @@ -19,7 +19,6 @@ import java.util.Properties; -import static org.hibernate.internal.util.config.ConfigurationHelper.getInt; import static org.hibernate.internal.util.config.ConfigurationHelper.getString; /** @@ -71,16 +70,6 @@ protected String determineSegmentValue(Properties params) { return null; } - @Override - protected int determineInitialValue(Properties params) { - return getInt( SequenceStyleGenerator.INITIAL_PARAM, params, SequenceStyleGenerator.DEFAULT_INITIAL_VALUE ); - } - - @Override - protected int determineIncrement(Properties params) { - return getInt( SequenceStyleGenerator.INCREMENT_PARAM, params, SequenceStyleGenerator.DEFAULT_INCREMENT_SIZE ); - } - @Override protected Object[] updateParameters(long currentValue, long updatedValue) { return new Object[] { updatedValue, currentValue }; diff --git a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/id/impl/TableReactiveIdentifierGenerator.java b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/id/impl/TableReactiveIdentifierGenerator.java index 79fb63aa6..21a863b0b 100644 --- a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/id/impl/TableReactiveIdentifierGenerator.java +++ b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/id/impl/TableReactiveIdentifierGenerator.java @@ -12,8 +12,6 @@ import org.hibernate.HibernateException; import org.hibernate.LockMode; import org.hibernate.LockOptions; -import org.hibernate.boot.model.relational.Database; -import org.hibernate.boot.model.relational.SqlStringGenerationContext; import org.hibernate.dialect.CockroachDialect; import org.hibernate.dialect.Dialect; import org.hibernate.dialect.OracleDialect; @@ -189,14 +187,6 @@ protected CompletionStage nextHiValue(ReactiveConnectionSupplier session) } ); } - @Override - public void registerExportables(Database database) { - } - - @Override - public void initialize(SqlStringGenerationContext context) { - } - @Override public Object generate(SharedSessionContractImplementor session, Object object) throws HibernateException { throw new UnsupportedOperationException(); diff --git a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/loader/ast/internal/DatabaseSnapshotExecutor.java b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/loader/ast/internal/DatabaseSnapshotExecutor.java index 3fdd5acf1..33e8465b2 100644 --- a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/loader/ast/internal/DatabaseSnapshotExecutor.java +++ b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/loader/ast/internal/DatabaseSnapshotExecutor.java @@ -79,7 +79,7 @@ class DatabaseSnapshotExecutor { DatabaseSnapshotExecutor::visitEmptyFetchList, true, new LoadQueryInfluencers( sessionFactory ), - sessionFactory + sessionFactory.getSqlTranslationEngine() ); final NavigablePath rootPath = new NavigablePath( entityDescriptor.getEntityName() ); diff --git a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/loader/ast/internal/ReactiveCollectionBatchLoaderArrayParam.java b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/loader/ast/internal/ReactiveCollectionBatchLoaderArrayParam.java index efeafdd02..0960a2ebc 100644 --- a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/loader/ast/internal/ReactiveCollectionBatchLoaderArrayParam.java +++ b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/loader/ast/internal/ReactiveCollectionBatchLoaderArrayParam.java @@ -18,9 +18,9 @@ import org.hibernate.loader.ast.internal.LoaderSelectBuilder; import org.hibernate.loader.ast.internal.MultiKeyLoadHelper; import org.hibernate.loader.ast.spi.SqlArrayMultiKeyLoader; +import org.hibernate.metamodel.mapping.ForeignKeyDescriptor; import org.hibernate.metamodel.mapping.JdbcMapping; import org.hibernate.metamodel.mapping.PluralAttributeMapping; -import org.hibernate.metamodel.mapping.internal.SimpleForeignKeyDescriptor; import org.hibernate.query.spi.QueryOptions; import org.hibernate.reactive.sql.exec.internal.StandardReactiveSelectExecutor; import org.hibernate.reactive.sql.results.spi.ReactiveListResultsConsumer; @@ -34,7 +34,6 @@ import org.hibernate.sql.exec.spi.JdbcParameterBindings; import org.hibernate.sql.exec.spi.JdbcParametersList; import org.hibernate.sql.results.internal.RowTransformerStandardImpl; -import org.hibernate.type.BasicType; import static org.hibernate.loader.ast.internal.MultiKeyLoadLogging.MULTI_KEY_LOAD_LOGGER; @@ -65,18 +64,14 @@ public ReactiveCollectionBatchLoaderArrayParam( ); } - final SimpleForeignKeyDescriptor keyDescriptor = (SimpleForeignKeyDescriptor) getLoadable().getKeyDescriptor(); - + final ForeignKeyDescriptor keyDescriptor = getLoadable().getKeyDescriptor(); + final JdbcMapping jdbcMapping = keyDescriptor.getSingleJdbcMapping(); + final Class jdbcJavaTypeClass = jdbcMapping.getJdbcJavaType().getJavaTypeClass(); arrayElementType = keyDescriptor.getJavaType().getJavaTypeClass(); - Class arrayClass = Array.newInstance( arrayElementType, 0 ).getClass(); - final BasicType arrayBasicType = getSessionFactory().getTypeConfiguration() - .getBasicTypeRegistry() - .getRegisteredType( arrayClass ); arrayJdbcMapping = MultiKeyLoadHelper.resolveArrayJdbcMapping( - arrayBasicType, - keyDescriptor.getJdbcMapping(), - arrayClass, + keyDescriptor.getSingleJdbcMapping(), + jdbcJavaTypeClass, getSessionFactory() ); diff --git a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/loader/ast/internal/ReactiveEntityBatchLoaderArrayParam.java b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/loader/ast/internal/ReactiveEntityBatchLoaderArrayParam.java index 9ff3c2ba7..ba69fd407 100644 --- a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/loader/ast/internal/ReactiveEntityBatchLoaderArrayParam.java +++ b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/loader/ast/internal/ReactiveEntityBatchLoaderArrayParam.java @@ -63,12 +63,10 @@ public ReactiveEntityBatchLoaderArrayParam( } identifierMapping = (BasicEntityIdentifierMapping) getLoadable().getIdentifierMapping(); - final Class arrayClass = - Array.newInstance( identifierMapping.getJavaType().getJavaTypeClass(), 0 ).getClass(); + final Class idClass = identifierMapping.getJavaType().getJavaTypeClass(); arrayJdbcMapping = MultiKeyLoadHelper.resolveArrayJdbcMapping( - sessionFactory.getTypeConfiguration().getBasicTypeRegistry().getRegisteredType( arrayClass ), identifierMapping.getJdbcMapping(), - arrayClass, + idClass, sessionFactory ); diff --git a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/loader/ast/internal/ReactiveMultiIdEntityLoaderArrayParam.java b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/loader/ast/internal/ReactiveMultiIdEntityLoaderArrayParam.java index fd7cb8794..8495d115b 100644 --- a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/loader/ast/internal/ReactiveMultiIdEntityLoaderArrayParam.java +++ b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/loader/ast/internal/ReactiveMultiIdEntityLoaderArrayParam.java @@ -21,17 +21,15 @@ import org.hibernate.engine.spi.SessionFactoryImplementor; import org.hibernate.engine.spi.SubselectFetch; import org.hibernate.event.spi.EventSource; -import org.hibernate.event.spi.LoadEvent; -import org.hibernate.event.spi.LoadEventListener; -import org.hibernate.loader.ast.internal.CacheEntityLoaderHelper; -import org.hibernate.loader.ast.internal.LoaderHelper; import org.hibernate.loader.ast.internal.LoaderSelectBuilder; import org.hibernate.loader.ast.internal.MultiIdEntityLoaderArrayParam; import org.hibernate.loader.ast.internal.MultiKeyLoadLogging; import org.hibernate.loader.ast.spi.MultiIdLoadOptions; +import org.hibernate.loader.internal.CacheLoadHelper.PersistenceContextEntry; import org.hibernate.metamodel.mapping.BasicEntityIdentifierMapping; import org.hibernate.metamodel.mapping.EntityMappingType; import org.hibernate.metamodel.mapping.JdbcMapping; +import org.hibernate.persister.entity.EntityPersister; import org.hibernate.query.spi.QueryOptions; import org.hibernate.reactive.sql.exec.internal.StandardReactiveSelectExecutor; import org.hibernate.reactive.sql.results.spi.ReactiveListResultsConsumer; @@ -44,11 +42,12 @@ import org.hibernate.sql.exec.spi.JdbcParameterBindings; import org.hibernate.sql.exec.spi.JdbcParametersList; import org.hibernate.sql.results.internal.RowTransformerStandardImpl; -import org.hibernate.type.BasicType; +import static org.hibernate.event.spi.LoadEventListener.GET; import static org.hibernate.internal.util.collections.CollectionHelper.arrayList; import static org.hibernate.internal.util.collections.CollectionHelper.isEmpty; import static org.hibernate.loader.ast.internal.MultiKeyLoadHelper.resolveArrayJdbcMapping; +import static org.hibernate.loader.internal.CacheLoadHelper.loadFromSessionCache; import static org.hibernate.reactive.loader.ast.internal.ReactiveLoaderHelper.loadByArrayParameter; import static org.hibernate.reactive.util.impl.CompletionStages.completedFuture; import static org.hibernate.reactive.util.impl.CompletionStages.loop; @@ -66,16 +65,12 @@ public ReactiveMultiIdEntityLoaderArrayParam( EntityMappingType entityDescriptor, SessionFactoryImplementor sessionFactory) { super( entityDescriptor, sessionFactory ); - final Class arrayClass = createTypedArray( 0 ).getClass(); - JdbcMapping jdbcMapping = getIdentifierMapping().getJdbcMapping(); - BasicType registeredType = getSessionFactory().getTypeConfiguration() - .getBasicTypeRegistry() - .getRegisteredType( arrayClass ); - JdbcMapping arrayJdbcMapping1 = resolveArrayJdbcMapping( registeredType, jdbcMapping, arrayClass, getSessionFactory() ); -// JavaType objectJavaType = getSessionFactory().getTypeConfiguration() -// .getJavaTypeRegistry() -// .resolveDescriptor( ReactiveArrayJdbcType.class ); - arrayJdbcMapping = arrayJdbcMapping1; + final Class idClass = getIdentifierMapping().getJavaType().getJavaTypeClass(); + arrayJdbcMapping = resolveArrayJdbcMapping( + getIdentifierMapping().getJdbcMapping(), + idClass, + getSessionFactory() + ); jdbcParameter = new JdbcParameterImpl( arrayJdbcMapping ); } @@ -113,24 +108,17 @@ protected CompletionStage> performOrderedMultiLoad( final EntityKey entityKey = new EntityKey( id, getLoadable().getEntityPersister() ); if ( loadOptions.isSessionCheckingEnabled() || loadOptions.isSecondLevelCacheCheckingEnabled() ) { - LoadEvent loadEvent = new LoadEvent( - id, - getLoadable().getJavaType().getJavaTypeClass().getName(), - lockOptions, - session, - LoaderHelper.getReadOnlyFromLoadQueryInfluencers( session ) - ); - Object managedEntity = null; if ( loadOptions.isSessionCheckingEnabled() ) { // look for it in the Session first - final CacheEntityLoaderHelper.PersistenceContextEntry persistenceContextEntry = CacheEntityLoaderHelper.loadFromSessionCacheStatic( - loadEvent, + final PersistenceContextEntry persistenceContextEntry = loadFromSessionCache( entityKey, - LoadEventListener.GET + lockOptions, + GET, + session ); - managedEntity = persistenceContextEntry.getEntity(); + managedEntity = persistenceContextEntry.entity(); if ( managedEntity != null && !loadOptions.isReturnOfDeletedEntitiesEnabled() @@ -142,12 +130,9 @@ protected CompletionStage> performOrderedMultiLoad( } if ( managedEntity == null && loadOptions.isSecondLevelCacheCheckingEnabled() ) { + final EntityPersister persister = getLoadable().getEntityPersister(); // look for it in the SessionFactory - managedEntity = CacheEntityLoaderHelper.INSTANCE.loadFromSecondLevelCache( - loadEvent, - getLoadable().getEntityPersister(), - entityKey - ); + managedEntity = session.loadFromSecondLevelCache( persister, entityKey, null, lockOptions.getLockMode() ); } if ( managedEntity != null ) { @@ -217,9 +202,7 @@ protected CompletionStage> performOrderedMultiLoad( } ) .thenApply( ignore -> { final PersistenceContext persistenceContext = session.getPersistenceContext(); - for ( int i = 0; i < idsToLoadFromDatabaseResultIndexes.size(); i++ ) { - final Integer resultIndex = idsToLoadFromDatabaseResultIndexes.get( i ); - + for ( final Integer resultIndex : idsToLoadFromDatabaseResultIndexes ) { // the element value at this position in the result List should be // the EntityKey for that entity - reuse it final EntityKey entityKey = (EntityKey) result.get( resultIndex ); @@ -337,32 +320,24 @@ protected final K[] processResolvableEntities( for ( int i = 0; i < ids.length; i++ ) { final Object id; if ( coerce ) { - //noinspection unchecked - id = (K) getLoadable().getIdentifierMapping().getJavaType().coerce( ids[i], session ); + id = getLoadable().getIdentifierMapping().getJavaType().coerce( ids[i], session ); } else { id = ids[i]; } final EntityKey entityKey = new EntityKey( id, getLoadable().getEntityPersister() ); - final LoadEvent loadEvent = new LoadEvent( - id, - getLoadable().getJavaType().getJavaTypeClass().getName(), - lockOptions, - session, - LoaderHelper.getReadOnlyFromLoadQueryInfluencers( session ) - ); - Object resolvedEntity = null; // look for it in the Session first - final CacheEntityLoaderHelper.PersistenceContextEntry persistenceContextEntry = CacheEntityLoaderHelper.loadFromSessionCacheStatic( - loadEvent, + final PersistenceContextEntry persistenceContextEntry = loadFromSessionCache( entityKey, - LoadEventListener.GET + lockOptions, + GET, + session ); if ( loadOptions.isSessionCheckingEnabled() ) { - resolvedEntity = persistenceContextEntry.getEntity(); + resolvedEntity = persistenceContextEntry.entity(); if ( resolvedEntity != null && !loadOptions.isReturnOfDeletedEntitiesEnabled() @@ -374,11 +349,8 @@ protected final K[] processResolvableEntities( } if ( resolvedEntity == null && loadOptions.isSecondLevelCacheCheckingEnabled() ) { - resolvedEntity = CacheEntityLoaderHelper.INSTANCE.loadFromSecondLevelCache( - loadEvent, - getLoadable().getEntityPersister(), - entityKey - ); + final EntityPersister persister = getLoadable().getEntityPersister(); + resolvedEntity = session.loadFromSecondLevelCache( persister, entityKey, null, lockOptions.getLockMode() ); } if ( resolvedEntity != null ) { @@ -391,7 +363,6 @@ protected final K[] processResolvableEntities( if ( nonResolvedIds == null ) { nonResolvedIds = new ArrayList<>(); } - //noinspection unchecked,CastCanBeRemovedNarrowingVariableType nonResolvedIds.add( (K) id ); } } diff --git a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/loader/ast/internal/ReactiveMultiIdEntityLoaderStandard.java b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/loader/ast/internal/ReactiveMultiIdEntityLoaderStandard.java index 9a87f2359..92f4e996a 100644 --- a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/loader/ast/internal/ReactiveMultiIdEntityLoaderStandard.java +++ b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/loader/ast/internal/ReactiveMultiIdEntityLoaderStandard.java @@ -20,19 +20,15 @@ import org.hibernate.engine.jdbc.spi.JdbcServices; import org.hibernate.engine.spi.EntityEntry; import org.hibernate.engine.spi.EntityKey; -import org.hibernate.engine.spi.LoadQueryInfluencers; import org.hibernate.engine.spi.PersistenceContext; import org.hibernate.engine.spi.SessionFactoryImplementor; import org.hibernate.engine.spi.SharedSessionContractImplementor; import org.hibernate.engine.spi.SubselectFetch; import org.hibernate.event.spi.EventSource; -import org.hibernate.event.spi.LoadEvent; -import org.hibernate.event.spi.LoadEventListener; import org.hibernate.internal.util.collections.CollectionHelper; -import org.hibernate.loader.ast.internal.CacheEntityLoaderHelper; -import org.hibernate.loader.ast.internal.LoaderHelper; import org.hibernate.loader.ast.internal.LoaderSelectBuilder; import org.hibernate.loader.ast.spi.MultiIdLoadOptions; +import org.hibernate.loader.internal.CacheLoadHelper.PersistenceContextEntry; import org.hibernate.mapping.PersistentClass; import org.hibernate.persister.entity.EntityPersister; import org.hibernate.query.spi.QueryOptions; @@ -50,6 +46,8 @@ import org.hibernate.sql.exec.spi.JdbcParametersList; import org.hibernate.sql.results.internal.RowTransformerStandardImpl; +import static org.hibernate.event.spi.LoadEventListener.GET; +import static org.hibernate.loader.internal.CacheLoadHelper.loadFromSessionCache; import static org.hibernate.reactive.util.impl.CompletionStages.completedFuture; import static org.hibernate.reactive.util.impl.CompletionStages.loop; import static org.hibernate.reactive.util.impl.CompletionStages.voidFuture; @@ -114,24 +112,17 @@ protected CompletionStage> performOrderedMultiLoad( final EntityKey entityKey = new EntityKey( id, getLoadable().getEntityPersister() ); if ( loadOptions.isSessionCheckingEnabled() || loadOptions.isSecondLevelCacheCheckingEnabled() ) { - LoadEvent loadEvent = new LoadEvent( - id, - getLoadable().getJavaType().getJavaTypeClass().getName(), - lockOptions, - session, - LoaderHelper.getReadOnlyFromLoadQueryInfluencers( session ) - ); - Object managedEntity = null; if ( loadOptions.isSessionCheckingEnabled() ) { // look for it in the Session first - CacheEntityLoaderHelper.PersistenceContextEntry persistenceContextEntry = CacheEntityLoaderHelper.INSTANCE.loadFromSessionCache( - loadEvent, + PersistenceContextEntry persistenceContextEntry = loadFromSessionCache( entityKey, - LoadEventListener.GET + lockOptions, + GET, + session ); - managedEntity = persistenceContextEntry.getEntity(); + managedEntity = persistenceContextEntry.entity(); if ( managedEntity != null && !loadOptions.isReturnOfDeletedEntitiesEnabled() && !persistenceContextEntry.isManaged() ) { // put a null in the result @@ -141,12 +132,10 @@ protected CompletionStage> performOrderedMultiLoad( } if ( managedEntity == null && loadOptions.isSecondLevelCacheCheckingEnabled() ) { + final EntityPersister persister = getLoadable().getEntityPersister(); // look for it in the SessionFactory - managedEntity = CacheEntityLoaderHelper.INSTANCE.loadFromSecondLevelCache( - loadEvent, - getLoadable().getEntityPersister(), - entityKey - ); + managedEntity = session + .loadFromSecondLevelCache( persister, entityKey, null, lockOptions.getLockMode() ); } if ( managedEntity != null ) { @@ -324,34 +313,26 @@ protected CompletionStage> performUnorderedMultiLoad( final List nonManagedIds = new ArrayList<>(); final boolean coerce = !getSessionFactory().getJpaMetamodel().getJpaCompliance().isLoadByIdComplianceEnabled(); - for ( int i = 0; i < ids.length; i++ ) { + for ( Object o : ids ) { final Object id = coerce - ? getEntityDescriptor().getIdentifierMapping().getJavaType().coerce( ids[i], session ) - : ids[i]; + ? getEntityDescriptor().getIdentifierMapping().getJavaType().coerce( o, session ) + : o; final EntityKey entityKey = new EntityKey( id, getLoadable().getEntityPersister() ); - LoadEvent loadEvent = new LoadEvent( - id, - getLoadable().getJavaType().getJavaTypeClass().getName(), - lockOptions, - session, - getReadOnlyFromLoadQueryInfluencers( session ) - ); - - Object managedEntity = null; + Object cachedEntity = null; // look for it in the Session first - CacheEntityLoaderHelper.PersistenceContextEntry persistenceContextEntry = CacheEntityLoaderHelper.INSTANCE - .loadFromSessionCache( - loadEvent, - entityKey, - LoadEventListener.GET - ); + PersistenceContextEntry persistenceContextEntry = loadFromSessionCache( + entityKey, + lockOptions, + GET, + session + ); if ( loadOptions.isSessionCheckingEnabled() ) { - managedEntity = persistenceContextEntry.getEntity(); + cachedEntity = persistenceContextEntry.entity(); - if ( managedEntity != null + if ( cachedEntity != null && !loadOptions.isReturnOfDeletedEntitiesEnabled() && !persistenceContextEntry.isManaged() ) { foundAnyManagedEntities = true; @@ -360,18 +341,20 @@ protected CompletionStage> performUnorderedMultiLoad( } } - if ( managedEntity == null && loadOptions.isSecondLevelCacheCheckingEnabled() ) { - managedEntity = CacheEntityLoaderHelper.INSTANCE.loadFromSecondLevelCache( - loadEvent, - getLoadable().getEntityPersister(), - entityKey + if ( cachedEntity == null && loadOptions.isSecondLevelCacheCheckingEnabled() ) { + final EntityPersister persister = getLoadable().getEntityPersister(); + cachedEntity = session.loadFromSecondLevelCache( + persister, + entityKey, + null, + lockOptions.getLockMode() ); } - if ( managedEntity != null ) { + if ( cachedEntity != null ) { foundAnyManagedEntities = true; //noinspection unchecked - result.add( (T) managedEntity ); + result.add( (T) cachedEntity ); } else { nonManagedIds.add( id ); @@ -427,14 +410,4 @@ protected CompletionStage> performUnorderedMultiLoad( } ) .thenApply( v -> result ); } - - private Boolean getReadOnlyFromLoadQueryInfluencers(SharedSessionContractImplementor session) { - Boolean readOnly = null; - final LoadQueryInfluencers loadQueryInfluencers = session.getLoadQueryInfluencers(); - if ( loadQueryInfluencers != null ) { - readOnly = loadQueryInfluencers.getReadOnly(); - } - return readOnly; - } - } diff --git a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/loader/ast/internal/ReactiveNaturalIdLoaderDelegate.java b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/loader/ast/internal/ReactiveNaturalIdLoaderDelegate.java index 56fef5be9..08b83cd47 100644 --- a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/loader/ast/internal/ReactiveNaturalIdLoaderDelegate.java +++ b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/loader/ast/internal/ReactiveNaturalIdLoaderDelegate.java @@ -27,6 +27,7 @@ import org.hibernate.metamodel.mapping.NaturalIdMapping; import org.hibernate.query.internal.SimpleQueryOptions; import org.hibernate.query.spi.QueryOptions; +import org.hibernate.reactive.engine.impl.ReactiveCallbackImpl; import org.hibernate.reactive.loader.ast.spi.ReactiveNaturalIdLoader; import org.hibernate.reactive.sql.exec.internal.StandardReactiveSelectExecutor; import org.hibernate.reactive.sql.results.spi.ReactiveListResultsConsumer; @@ -38,7 +39,6 @@ import org.hibernate.sql.ast.tree.select.QuerySpec; import org.hibernate.sql.ast.tree.select.SelectStatement; import org.hibernate.sql.exec.internal.BaseExecutionContext; -import org.hibernate.sql.exec.internal.CallbackImpl; import org.hibernate.sql.exec.internal.JdbcParameterBindingsImpl; import org.hibernate.sql.exec.spi.Callback; import org.hibernate.sql.exec.spi.JdbcOperationQuerySelect; @@ -238,7 +238,7 @@ public CompletionStage reactiveSelectByNaturalId( fetchProcessor, true, new LoadQueryInfluencers( sessionFactory ), - sessionFactory + sessionFactory.getSqlTranslationEngine() ); final TableGroup rootTableGroup = entityDescriptor().createRootTableGroup( @@ -335,7 +335,7 @@ public NaturalIdLoaderWithOptionsExecutionContext( QueryOptions queryOptions) { super( session ); this.queryOptions = queryOptions; - callback = new CallbackImpl(); + callback = new ReactiveCallbackImpl(); } @Override diff --git a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/loader/ast/internal/ReactiveSingleIdEntityLoaderProvidedQueryImpl.java b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/loader/ast/internal/ReactiveSingleIdEntityLoaderProvidedQueryImpl.java index 6b849d346..b2ec82649 100644 --- a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/loader/ast/internal/ReactiveSingleIdEntityLoaderProvidedQueryImpl.java +++ b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/loader/ast/internal/ReactiveSingleIdEntityLoaderProvidedQueryImpl.java @@ -46,7 +46,7 @@ public EntityMappingType getLoadable() { public CompletionStage load(Object pkValue, LockOptions lockOptions, Boolean readOnly, SharedSessionContractImplementor session) { // noinspection unchecked final QueryImplementor query = namedQueryMemento - .toQuery( session, (Class) entityDescriptor.getMappedJavaType().getJavaTypeClass() ); + .toQuery( session, entityDescriptor.getMappedJavaType().getJavaTypeClass() ); //noinspection unchecked query.setParameter( (Parameter) query.getParameters().iterator().next(), pkValue ); diff --git a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/loader/ast/internal/ReactiveSingleIdLoadPlan.java b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/loader/ast/internal/ReactiveSingleIdLoadPlan.java index 83c3292f5..79994adc8 100644 --- a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/loader/ast/internal/ReactiveSingleIdLoadPlan.java +++ b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/loader/ast/internal/ReactiveSingleIdLoadPlan.java @@ -20,17 +20,19 @@ import org.hibernate.query.internal.SimpleQueryOptions; import org.hibernate.query.spi.QueryOptions; import org.hibernate.query.spi.QueryParameterBindings; +import org.hibernate.reactive.engine.impl.ReactiveCallbackImpl; import org.hibernate.reactive.sql.exec.internal.StandardReactiveSelectExecutor; import org.hibernate.reactive.sql.results.spi.ReactiveListResultsConsumer; import org.hibernate.resource.jdbc.spi.LogicalConnectionImplementor; import org.hibernate.sql.ast.tree.select.SelectStatement; -import org.hibernate.sql.exec.internal.CallbackImpl; import org.hibernate.sql.exec.internal.JdbcParameterBindingsImpl; import org.hibernate.sql.exec.spi.Callback; import org.hibernate.sql.exec.spi.ExecutionContext; import org.hibernate.sql.exec.spi.JdbcParameterBindings; import org.hibernate.sql.exec.spi.JdbcParametersList; +import static org.hibernate.reactive.util.impl.CompletionStages.voidFuture; + public class ReactiveSingleIdLoadPlan extends SingleIdLoadPlan> { public ReactiveSingleIdLoadPlan( @@ -61,7 +63,7 @@ public CompletionStage load(Object restrictedValue, Object entityInstance, Bo } assert offset == getJdbcParameters().size(); final QueryOptions queryOptions = new SimpleQueryOptions( getLockOptions(), readOnly ); - final Callback callback = new CallbackImpl(); + final ReactiveCallbackImpl callback = new ReactiveCallbackImpl(); EntityMappingType loadable = (EntityMappingType) getLoadable(); ExecutionContext executionContext = executionContext( restrictedValue, @@ -74,17 +76,19 @@ public CompletionStage load(Object restrictedValue, Object entityInstance, Bo // FIXME: Should we get this from jdbcServices.getSelectExecutor()? return StandardReactiveSelectExecutor.INSTANCE .list( getJdbcSelect(), jdbcParameterBindings, executionContext, getRowTransformer(), resultConsumer( singleResultExpected ) ) - .thenApply( this::extractEntity ) - .thenApply( entity -> { - invokeAfterLoadActions( callback, session, entity ); - return (T) entity; - } ); + .thenCompose( list -> { + Object entity = extractEntity( list ); + return invokeAfterLoadActions( callback, session, entity ) + .thenApply( v -> (T) entity ); + } + ); } - private void invokeAfterLoadActions(Callback callback, SharedSessionContractImplementor session, T entity) { - if ( entity != null && getLoadable() != null) { - callback.invokeAfterLoadActions( entity, (EntityMappingType) getLoadable(), session ); + private CompletionStage invokeAfterLoadActions(ReactiveCallbackImpl callback, SharedSessionContractImplementor session, G entity) { + if ( entity != null && getLoadable() != null ) { + return callback.invokeReactiveLoadActions( entity, (EntityMappingType) getLoadable(), session ); } + return voidFuture(); } private Object extractEntity(List list) { diff --git a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/loader/ast/internal/ReactiveSingleUniqueKeyEntityLoaderStandard.java b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/loader/ast/internal/ReactiveSingleUniqueKeyEntityLoaderStandard.java index 62e5d0d44..09490cdad 100644 --- a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/loader/ast/internal/ReactiveSingleUniqueKeyEntityLoaderStandard.java +++ b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/loader/ast/internal/ReactiveSingleUniqueKeyEntityLoaderStandard.java @@ -24,13 +24,13 @@ import org.hibernate.metamodel.mapping.SingularAttributeMapping; import org.hibernate.metamodel.mapping.internal.ToOneAttributeMapping; import org.hibernate.query.spi.QueryOptions; +import org.hibernate.reactive.engine.impl.ReactiveCallbackImpl; import org.hibernate.reactive.loader.ast.spi.ReactiveSingleUniqueKeyEntityLoader; import org.hibernate.reactive.sql.exec.internal.StandardReactiveSelectExecutor; import org.hibernate.reactive.sql.results.spi.ReactiveListResultsConsumer; import org.hibernate.sql.ast.SqlAstTranslatorFactory; import org.hibernate.sql.ast.tree.select.SelectStatement; import org.hibernate.sql.exec.internal.BaseExecutionContext; -import org.hibernate.sql.exec.internal.CallbackImpl; import org.hibernate.sql.exec.internal.JdbcParameterBindingsImpl; import org.hibernate.sql.exec.spi.Callback; import org.hibernate.sql.exec.spi.JdbcOperationQuerySelect; @@ -179,7 +179,7 @@ public SingleUKEntityLoaderExecutionContext(SharedSessionContractImplementor ses super( session ); //Careful, readOnly is possibly null this.queryOptions = readOnly == null ? QueryOptions.NONE : readOnly ? QueryOptions.READ_ONLY : QueryOptions.READ_WRITE; - callback = new CallbackImpl(); + callback = new ReactiveCallbackImpl(); } @Override diff --git a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/loader/ast/internal/ReactiveStandardBatchLoaderFactory.java b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/loader/ast/internal/ReactiveStandardBatchLoaderFactory.java index 5d5c03fb5..fa5d075ba 100644 --- a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/loader/ast/internal/ReactiveStandardBatchLoaderFactory.java +++ b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/loader/ast/internal/ReactiveStandardBatchLoaderFactory.java @@ -33,7 +33,7 @@ public EntityBatchLoader createEntityBatchLoader( // NOTE : don't use the EntityIdentifierMapping here because it will not be known until later final Type identifierType = entityDescriptor.getEntityPersister().getIdentifierType(); - final int idColumnCount = identifierType.getColumnSpan( factory ); + final int idColumnCount = identifierType.getColumnSpan( factory.getRuntimeMetamodels() ); if ( idColumnCount == 1 && MultiKeyLoadHelper.supportsSqlArrayType( dialect ) diff --git a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/loader/ast/spi/ReactiveAfterLoadAction.java b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/loader/ast/spi/ReactiveAfterLoadAction.java new file mode 100644 index 000000000..e7e20d2e8 --- /dev/null +++ b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/loader/ast/spi/ReactiveAfterLoadAction.java @@ -0,0 +1,26 @@ +/* Hibernate, Relational Persistence for Idiomatic Java + * + * SPDX-License-Identifier: Apache-2.0 + * Copyright: Red Hat Inc. and Hibernate Authors + */ +package org.hibernate.reactive.loader.ast.spi; + +import java.util.concurrent.CompletionStage; + +import org.hibernate.engine.spi.SharedSessionContractImplementor; +import org.hibernate.metamodel.mapping.EntityMappingType; + +/** + * Reactive version of {@link org.hibernate.loader.ast.spi.AfterLoadAction} + */ +public interface ReactiveAfterLoadAction { + /** + * @see org.hibernate.loader.ast.spi.AfterLoadAction#afterLoad(Object, EntityMappingType, SharedSessionContractImplementor) + * + * The action trigger - the {@code entity} is being loaded + */ + CompletionStage reactiveAfterLoad( + Object entity, + EntityMappingType entityMappingType, + SharedSessionContractImplementor session); +} diff --git a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/loader/entity/ReactiveCacheEntityLoaderHelper.java b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/loader/entity/ReactiveCacheEntityLoaderHelper.java deleted file mode 100644 index 703148cd7..000000000 --- a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/loader/entity/ReactiveCacheEntityLoaderHelper.java +++ /dev/null @@ -1,148 +0,0 @@ -/* Hibernate, Relational Persistence for Idiomatic Java - * - * SPDX-License-Identifier: Apache-2.0 - * Copyright: Red Hat Inc. and Hibernate Authors - */ -package org.hibernate.reactive.loader.entity; - -import static org.hibernate.loader.ast.internal.LoaderHelper.upgradeLock; -import org.hibernate.HibernateException; -import org.hibernate.LockMode; -import org.hibernate.LockOptions; -import org.hibernate.ObjectDeletedException; -import org.hibernate.cache.spi.access.EntityDataAccess; -import org.hibernate.cache.spi.access.SoftLock; -import org.hibernate.engine.spi.EntityEntry; -import org.hibernate.engine.spi.EntityKey; -import org.hibernate.engine.spi.SessionImplementor; -import org.hibernate.engine.spi.Status; -import org.hibernate.event.spi.EventSource; -import org.hibernate.event.spi.LoadEvent; -import org.hibernate.event.spi.LoadEventListener; -import org.hibernate.internal.CoreLogging; -import org.hibernate.internal.CoreMessageLogger; -import org.hibernate.loader.ast.internal.CacheEntityLoaderHelper.EntityStatus; -import org.hibernate.loader.ast.internal.CacheEntityLoaderHelper.PersistenceContextEntry; -import org.hibernate.persister.entity.EntityPersister; -import org.hibernate.reactive.persister.entity.impl.ReactiveEntityPersister; -import org.hibernate.sql.results.LoadingLogger; - -/** - * @author Gavin King - * - * @see org.hibernate.loader.ast.internal.CacheEntityLoaderHelper - */ -public class ReactiveCacheEntityLoaderHelper { - - public static final ReactiveCacheEntityLoaderHelper INSTANCE = new ReactiveCacheEntityLoaderHelper(); - - private static final CoreMessageLogger LOG = CoreLogging.messageLogger( ReactiveCacheEntityLoaderHelper.class ); - - private ReactiveCacheEntityLoaderHelper() {} - - /** - * Attempts to locate the entity in the session-level cache. - *

- * If allowed to return nulls, then if the entity happens to be found in - * the session cache, we check the entity type for proper handling - * of entity hierarchies. - *

- * If checkDeleted was set to true, then if the entity is found in the - * session-level cache, its current status within the session cache - * is checked to see if it has previously been scheduled for deletion. - * - * @param event The load event - * @param keyToLoad The EntityKey representing the entity to be loaded. - * @param options The load options. - * - * @return The entity from the session-level cache, or null. - * - * @throws HibernateException Generally indicates problems applying a lock-mode. - */ - public PersistenceContextEntry loadFromSessionCache( - final LoadEvent event, - final EntityKey keyToLoad, - final LoadEventListener.LoadType options) throws HibernateException { - - SessionImplementor session = event.getSession(); - Object old = session.getEntityUsingInterceptor( keyToLoad ); - - if ( old != null ) { - // this object was already loaded - EntityEntry oldEntry = session.getPersistenceContext().getEntry( old ); - if ( options.isCheckDeleted() ) { - if ( oldEntry.getStatus().isDeletedOrGone() ) { - LoadingLogger.LOGGER.debug( - "Load request found matching entity in context, but it is scheduled for removal; returning null" ); - return new PersistenceContextEntry( old, EntityStatus.REMOVED_ENTITY_MARKER ); - } - } - if ( options.isAllowNulls() ) { - final EntityPersister persister = event.getSession() - .getFactory() - .getRuntimeMetamodels() - .getMappingMetamodel() - .getEntityDescriptor( keyToLoad.getEntityName() ); - if ( !persister.isInstance( old ) ) { - LOG.debug( - "Load request found matching entity in context, but the matched entity was of an inconsistent return type; returning null" - ); - return new PersistenceContextEntry( old, EntityStatus.INCONSISTENT_RTN_CLASS_MARKER ); - } - } - upgradeLock( old, oldEntry, event.getLockOptions(), event.getSession() ); - } - - return new PersistenceContextEntry( old, EntityStatus.MANAGED ); - } - - /** - * see org.hibernate.event.internal.AbstractLockUpgradeEventListener#upgradeLock(Object, EntityEntry, LockOptions, EventSource) - */ - private static void upgradeLock(Object object, EntityEntry entry, LockOptions lockOptions, EventSource source) { - - LockMode requestedLockMode = lockOptions.getLockMode(); - if ( requestedLockMode.greaterThan( entry.getLockMode() ) ) { - // The user requested a "greater" (i.e. more restrictive) form of pessimistic lock - - if ( entry.getStatus() != Status.MANAGED ) { - throw new ObjectDeletedException( - "attempted to lock a deleted instance", - entry.getId(), - entry.getPersister().getEntityName() - ); - } - - final EntityPersister persister = entry.getPersister(); - final boolean cachingEnabled = persister.canWriteToCache(); - SoftLock lock = null; - Object ck = null; - try { - if ( cachingEnabled ) { - EntityDataAccess cache = persister.getCacheAccessStrategy(); - ck = cache.generateCacheKey( entry.getId(), persister, source.getFactory(), source.getTenantIdentifier() ); - lock = cache.lockItem( source, ck, entry.getVersion() ); - } - - if ( persister.isVersioned() && requestedLockMode == LockMode.PESSIMISTIC_FORCE_INCREMENT ) { - // todo : should we check the current isolation mode explicitly? - Object nextVersion = persister.forceVersionIncrement( entry.getId(), entry.getVersion(), source ); - entry.forceLocked( object, nextVersion ); - } - else { - ( (ReactiveEntityPersister) persister ) - .reactiveLock( entry.getId(), entry.getVersion(), object, lockOptions, source ); - } - entry.setLockMode( requestedLockMode ); - } - finally { - // the database now holds a lock + the object is flushed from the cache, - // so release the soft lock - if ( cachingEnabled ) { - persister.getCacheAccessStrategy().unlockItem( source, ck, lock ); - } - } - - } - } -} diff --git a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/persister/entity/impl/ReactiveAbstractEntityPersister.java b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/persister/entity/impl/ReactiveAbstractEntityPersister.java index a29799b23..c1015939c 100644 --- a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/persister/entity/impl/ReactiveAbstractEntityPersister.java +++ b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/persister/entity/impl/ReactiveAbstractEntityPersister.java @@ -39,13 +39,12 @@ import org.hibernate.engine.spi.SessionFactoryImplementor; import org.hibernate.engine.spi.SharedSessionContractImplementor; import org.hibernate.event.spi.EventSource; -import org.hibernate.event.spi.LoadEvent; import org.hibernate.generator.OnExecutionGenerator; import org.hibernate.generator.values.GeneratedValuesMutationDelegate; import org.hibernate.internal.util.collections.ArrayHelper; -import org.hibernate.loader.ast.internal.CacheEntityLoaderHelper; import org.hibernate.loader.ast.internal.LoaderSelectBuilder; import org.hibernate.loader.ast.spi.NaturalIdLoader; +import org.hibernate.loader.ast.spi.SingleIdEntityLoader; import org.hibernate.mapping.PersistentClass; import org.hibernate.metamodel.mapping.AttributeMapping; import org.hibernate.metamodel.mapping.AttributeMappingsList; @@ -222,7 +221,7 @@ default CompletionStage reactiveLock( offset++; } getIdentifierType().nullSafeSet( statement, id, offset, session ); - offset += getIdentifierType().getColumnSpan( getFactory() ); + offset += getIdentifierType().getColumnSpan( getFactory().getRuntimeMetamodels() ); if ( isVersioned() ) { getVersionType().nullSafeSet( statement, version, offset, session ); } @@ -521,26 +520,19 @@ private CompletionStage loadFromDatabaseOrCache( EntityKey entityKey, Object identifier) { - // note that stateless sessions don't interact with second-level cache - if ( session instanceof EventSource && canReadFromCache() ) { - Object cached = CacheEntityLoaderHelper.INSTANCE.loadFromSecondLevelCache( - new LoadEvent( identifier, entity, (EventSource) session, false ), - this, - entityKey - ); - if ( cached != null ) { - return completedFuture( cached ); + if ( canReadFromCache() && session.isEventSource() ) { + final EventSource eventSource = (EventSource) session; + Object loaded = eventSource.loadFromSecondLevelCache( this, entityKey, entity, LockMode.NONE ); + if ( loaded != null ) { + return completedFuture( loaded ); } } - - return getReactiveSingleIdEntityLoader().load( - identifier, - entity, - LockOptions.NONE, - session - ); + return ( (ReactiveSingleIdEntityLoader) determineLoaderToUse( session ) ) + .load( identifier, entity, LockOptions.NONE, session ); } + SingleIdEntityLoader determineLoaderToUse(SharedSessionContractImplementor session); + boolean initializeLazyProperty(String fieldName, Object entity, EntityEntry entry, int lazyIndex, Object selectedValue); Object initializeLazyProperty(String fieldName, Object entity, SharedSessionContractImplementor session); diff --git a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/persister/entity/impl/ReactiveEntityPersister.java b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/persister/entity/impl/ReactiveEntityPersister.java index ba365a463..ee35d9fca 100644 --- a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/persister/entity/impl/ReactiveEntityPersister.java +++ b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/persister/entity/impl/ReactiveEntityPersister.java @@ -16,6 +16,7 @@ import org.hibernate.generator.values.GeneratedValues; import org.hibernate.loader.ast.spi.MultiIdLoadOptions; import org.hibernate.persister.entity.EntityPersister; +import org.hibernate.reactive.persister.entity.mutation.ReactiveInsertCoordinator; import jakarta.persistence.metamodel.Attribute; @@ -33,7 +34,7 @@ public interface ReactiveEntityPersister extends EntityPersister { * @see EntityPersister#insert(Object, Object[], Object, SharedSessionContractImplementor) */ default CompletionStage insertReactive(Object id, Object[] fields, Object object, SharedSessionContractImplementor session) { - return insertReactive( id, fields, object, session ); + return ( (ReactiveInsertCoordinator) getInsertCoordinator() ).reactiveInsert( object, id, fields, session ); }; /** diff --git a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/persister/entity/impl/ReactiveJoinedSubclassEntityPersister.java b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/persister/entity/impl/ReactiveJoinedSubclassEntityPersister.java index 0de5391f0..c4e688ce6 100644 --- a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/persister/entity/impl/ReactiveJoinedSubclassEntityPersister.java +++ b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/persister/entity/impl/ReactiveJoinedSubclassEntityPersister.java @@ -139,6 +139,11 @@ protected AttributeMapping buildPluralAttributeMapping( ); } + @Override + public SingleIdEntityLoader determineLoaderToUse(SharedSessionContractImplementor session) { + return super.determineLoaderToUse( session ); + } + @Override protected InsertCoordinator buildInsertCoordinator() { return ReactiveCoordinatorFactory.buildInsertCoordinator( this, getFactory() ); diff --git a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/persister/entity/impl/ReactiveSingleTableEntityPersister.java b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/persister/entity/impl/ReactiveSingleTableEntityPersister.java index bc52a7b6e..72b8c040e 100644 --- a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/persister/entity/impl/ReactiveSingleTableEntityPersister.java +++ b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/persister/entity/impl/ReactiveSingleTableEntityPersister.java @@ -86,6 +86,11 @@ public GeneratedValuesMutationDelegate createInsertDelegate() { return ReactiveAbstractEntityPersister.super.createReactiveInsertDelegate(); } + @Override + public SingleIdEntityLoader determineLoaderToUse(SharedSessionContractImplementor session) { + return super.determineLoaderToUse( session ); + } + @Override protected GeneratedValuesMutationDelegate createUpdateDelegate() { return ReactiveAbstractEntityPersister.super.createReactiveUpdateDelegate(); diff --git a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/persister/entity/impl/ReactiveUnionSubclassEntityPersister.java b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/persister/entity/impl/ReactiveUnionSubclassEntityPersister.java index 420200027..c844f7644 100644 --- a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/persister/entity/impl/ReactiveUnionSubclassEntityPersister.java +++ b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/persister/entity/impl/ReactiveUnionSubclassEntityPersister.java @@ -139,6 +139,11 @@ protected AttributeMapping buildPluralAttributeMapping( ); } + @Override + public SingleIdEntityLoader determineLoaderToUse(SharedSessionContractImplementor session) { + return super.determineLoaderToUse( session ); + } + @Override public NaturalIdMapping generateNaturalIdMapping(MappingModelCreationProcess creationProcess, PersistentClass bootEntityDescriptor) { return ReactiveAbstractEntityPersister.super.generateNaturalIdMapping(creationProcess, bootEntityDescriptor); diff --git a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/persister/entity/mutation/ReactiveInsertCoordinatorStandard.java b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/persister/entity/mutation/ReactiveInsertCoordinatorStandard.java index db2671be9..3fa811b99 100644 --- a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/persister/entity/mutation/ReactiveInsertCoordinatorStandard.java +++ b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/persister/entity/mutation/ReactiveInsertCoordinatorStandard.java @@ -435,14 +435,12 @@ protected void breakDownJdbcValue( final String tableName = tableDetails.getTableName(); tableDetails.getKeyMapping().breakDownKeyJdbcValues( id, - (jdbcValue, columnMapping) -> { - jdbcValueBindings.bindValue( - jdbcValue, - tableName, - columnMapping.getColumnName(), - ParameterUsage.SET - ); - }, + (jdbcValue, columnMapping) -> jdbcValueBindings.bindValue( + jdbcValue, + tableName, + columnMapping.getColumnName(), + ParameterUsage.SET + ), session ); } diff --git a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/pool/impl/DefaultSqlClientPool.java b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/pool/impl/DefaultSqlClientPool.java index 35c3980e0..67476f71e 100644 --- a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/pool/impl/DefaultSqlClientPool.java +++ b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/pool/impl/DefaultSqlClientPool.java @@ -37,7 +37,6 @@ import io.vertx.sqlclient.spi.Driver; import static java.util.Collections.singletonList; -import static java.util.stream.Collectors.toList; /** * A pool of reactive connections backed by a Vert.x {@link Pool}. @@ -128,7 +127,7 @@ public void injectServices(ServiceRegistryImplementor serviceRegistry) { } @Override - public void configure(Map configuration) { + public void configure(Map configuration) { uri = jdbcUrl( configuration ); } @@ -247,7 +246,7 @@ private Driver findDriver(URI uri, ServiceConfigurationError originalError) { if ( selected.size() > 1 ) { List driverClasses = selected.stream() .map( driver -> driver.getClass().getCanonicalName() ) - .collect( toList() ); + .toList(); throw new ConfigurationException( "Multiple drivers found matching for URI scheme \"" + scheme + "\". Please, pick one: " + driverClasses, originalError ); } return selected.get( 0 ); diff --git a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/pool/impl/DefaultSqlClientPoolConfiguration.java b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/pool/impl/DefaultSqlClientPoolConfiguration.java index b60600bb8..e0613b78c 100644 --- a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/pool/impl/DefaultSqlClientPoolConfiguration.java +++ b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/pool/impl/DefaultSqlClientPoolConfiguration.java @@ -232,15 +232,15 @@ private int oraclePort(URI uri) { if ( s.indexOf( '/' ) != -1 ) { // Example: 1234/ s = s.substring( 0, s.indexOf( '/' ) ); - return Integer.valueOf( s ); + return Integer.parseInt( s ); } if ( s.indexOf( '?' ) != -1 ) { // Example: 1234?param=value s = s.substring( 0, s.indexOf( '?' ) ); - return Integer.valueOf( s ); + return Integer.parseInt( s ); } // Example: 1234 - return Integer.valueOf( s ); + return Integer.parseInt( s ); } return -1; } @@ -330,7 +330,7 @@ private int extractPort(URI uri) { if ( startOfPort == -1 ) { return -1; } - return Integer.valueOf( hostPortString.substring( startOfPort + 1 ) ); + return Integer.parseInt( hostPortString.substring( startOfPort + 1 ) ); } private String findHost(URI uri, String scheme) { @@ -348,7 +348,7 @@ private String findHost(URI uri, String scheme) { } private int findPort(URI uri, String scheme) { - int port = -1; + int port; if ( "oracle".equals( scheme ) ) { port = oraclePort( uri ); } diff --git a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/pool/impl/ExternalSqlClientPool.java b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/pool/impl/ExternalSqlClientPool.java index 602ecd7b0..86067882a 100644 --- a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/pool/impl/ExternalSqlClientPool.java +++ b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/pool/impl/ExternalSqlClientPool.java @@ -59,7 +59,7 @@ public final class ExternalSqlClientPool extends SqlClientPool { private final Pool pool; private final SqlStatementLogger sqlStatementLogger; - private SqlExceptionHelper sqlExceptionHelper; + private final SqlExceptionHelper sqlExceptionHelper; public ExternalSqlClientPool(Pool pool, SqlStatementLogger sqlStatementLogger, SqlExceptionHelper sqlExceptionHelper) { this.pool = pool; diff --git a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/provider/impl/ReactiveIntegrator.java b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/provider/impl/ReactiveIntegrator.java index 0d1876320..c1fb0deb9 100644 --- a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/provider/impl/ReactiveIntegrator.java +++ b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/provider/impl/ReactiveIntegrator.java @@ -25,11 +25,9 @@ import org.hibernate.reactive.event.impl.DefaultReactivePersistOnFlushEventListener; import org.hibernate.reactive.event.impl.DefaultReactivePostLoadEventListener; import org.hibernate.reactive.event.impl.DefaultReactiveRefreshEventListener; -import org.hibernate.reactive.event.impl.DefaultReactiveResolveNaturalIdEventListener; import org.hibernate.reactive.logging.impl.Log; import org.hibernate.reactive.logging.impl.LoggerFactory; import org.hibernate.service.ServiceRegistry; -import org.hibernate.service.spi.SessionFactoryServiceRegistry; /** * Integrates Hibernate Reactive with Hibernate ORM by @@ -48,10 +46,6 @@ public void integrate(Metadata metadata, BootstrapContext bootstrapContext, Sess attachEventContextManagingListenersIfRequired( sessionFactory.getServiceRegistry() ); } - @Override - public void disintegrate(SessionFactoryImplementor sessionFactory, SessionFactoryServiceRegistry serviceRegistry) { - } - private void attachEventContextManagingListenersIfRequired(ServiceRegistry serviceRegistry) { if ( ReactiveModeCheck.isReactiveRegistry( serviceRegistry ) ) { LOG.startHibernateReactive(); @@ -70,7 +64,6 @@ private void attachEventContextManagingListenersIfRequired(ServiceRegistry servi eventListenerRegistry.getEventListenerGroup( EventType.LOAD ).appendListener( new DefaultReactiveLoadEventListener() ); eventListenerRegistry.getEventListenerGroup( EventType.INIT_COLLECTION ).appendListener( new DefaultReactiveInitializeCollectionEventListener() ); eventListenerRegistry.getEventListenerGroup( EventType.POST_LOAD ).appendListener( new DefaultReactivePostLoadEventListener() ); - eventListenerRegistry.getEventListenerGroup( EventType.RESOLVE_NATURAL_ID ).appendListener( new DefaultReactiveResolveNaturalIdEventListener() ); } } } diff --git a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/provider/service/AbstractReactiveInformationSchemaBasedExtractorImpl.java b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/provider/service/AbstractReactiveInformationSchemaBasedExtractorImpl.java index 61a5534b4..dc7f2111e 100644 --- a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/provider/service/AbstractReactiveInformationSchemaBasedExtractorImpl.java +++ b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/provider/service/AbstractReactiveInformationSchemaBasedExtractorImpl.java @@ -192,7 +192,7 @@ protected boolean appendClauseAndParameterIfNotNullOrEmpty( StringBuilder sb, List parameters) { - if ( parameter != null && ( ! String.class.isInstance( parameter ) || ! ( (String) parameter ).isEmpty() ) ) { + if ( parameter != null && ( !( parameter instanceof String ) || !( (String) parameter ).isEmpty() ) ) { parameters.add( parameter ); sb.append( clause ); sb.append( parameterMarker( parameters.size() ) ); @@ -351,7 +351,7 @@ protected String getDatabaseCatalogColumnName(String catalogColumnName, String s * used for storing the schema name, or , if there * is no valid column containing the schema name. *

- * MySQL, for example, does not have a valid column in + * MySQL, for example, does not have a valid column * in the information_schema to store the schema name. * (@see MySqlReactiveInformationExtractorImpl) * diff --git a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/provider/service/MySqlReactiveInformationExtractorImpl.java b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/provider/service/MySqlReactiveInformationExtractorImpl.java index 6cc016dda..0504e44ee 100644 --- a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/provider/service/MySqlReactiveInformationExtractorImpl.java +++ b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/provider/service/MySqlReactiveInformationExtractorImpl.java @@ -46,11 +46,6 @@ protected int dataTypeCode(String typeName) { } } - @Override - protected String getResultSetTableTypesPhysicalTableConstant() { - return "BASE TABLE"; - } - protected String getDatabaseCatalogColumnName(String catalogColumnName, String schemaColumnName ) { return schemaColumnName; } @@ -64,7 +59,7 @@ protected T processPrimaryKeysResultSet( String catalogFilter, String schemaFilter, Identifier tableName, - ExtractionContext.ResultSetProcessor processor) throws SQLException { + ExtractionContext.ResultSetProcessor processor) { // This functionality is not used by ORM. throw new UnsupportedOperationException(); } diff --git a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/provider/service/PostgreSqlReactiveInformationExtractorImpl.java b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/provider/service/PostgreSqlReactiveInformationExtractorImpl.java index ee4a012fe..62fff7ecc 100644 --- a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/provider/service/PostgreSqlReactiveInformationExtractorImpl.java +++ b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/provider/service/PostgreSqlReactiveInformationExtractorImpl.java @@ -32,17 +32,12 @@ public PostgreSqlReactiveInformationExtractorImpl(ExtractionContext extractionCo super( extractionContext ); } - @Override - protected String getResultSetTableTypesPhysicalTableConstant() { - return "BASE TABLE"; - } - @Override protected T processPrimaryKeysResultSet( String catalogFilter, String schemaFilter, Identifier tableName, - ExtractionContext.ResultSetProcessor processor) throws SQLException { + ExtractionContext.ResultSetProcessor processor) { // This functionality is not used by ORM. throw new UnsupportedOperationException(); } diff --git a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/provider/service/SqlServerReactiveInformationExtractorImpl.java b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/provider/service/SqlServerReactiveInformationExtractorImpl.java index 2cec39ce7..eea7fc477 100644 --- a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/provider/service/SqlServerReactiveInformationExtractorImpl.java +++ b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/provider/service/SqlServerReactiveInformationExtractorImpl.java @@ -158,7 +158,7 @@ protected T processPrimaryKeysResultSet( String catalogFilter, String schemaFilter, Identifier tableName, - ExtractionContext.ResultSetProcessor processor) throws SQLException { + ExtractionContext.ResultSetProcessor processor) { throw new UnsupportedOperationException(); } diff --git a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/query/internal/ReactiveNamedObjectRepositoryImpl.java b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/query/internal/ReactiveNamedObjectRepositoryImpl.java index 2ac40168c..ef2d70afe 100644 --- a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/query/internal/ReactiveNamedObjectRepositoryImpl.java +++ b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/query/internal/ReactiveNamedObjectRepositoryImpl.java @@ -22,6 +22,7 @@ import org.hibernate.reactive.query.sql.spi.ReactiveNamedNativeQueryMemento; import org.hibernate.reactive.query.sql.spi.ReactiveNamedSqmQueryMemento; +import jakarta.persistence.Query; import jakarta.persistence.TypedQueryReference; public class ReactiveNamedObjectRepositoryImpl implements NamedObjectRepository { @@ -42,6 +43,11 @@ public NamedSqmQueryMemento getSqmQueryMemento(String queryName) { return wrapSqmQueryMemento( delegate.getSqmQueryMemento( queryName ) ); } + @Override + public void registerNamedQuery(String name, Query query) { + delegate.registerNamedQuery( name, query ); + } + @Override public void visitSqmQueryMementos(Consumer> action) { delegate.visitSqmQueryMementos( action ); diff --git a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/query/spi/ReactiveAbstractSelectionQuery.java b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/query/spi/ReactiveAbstractSelectionQuery.java index f01b5d315..1137e0a62 100644 --- a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/query/spi/ReactiveAbstractSelectionQuery.java +++ b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/query/spi/ReactiveAbstractSelectionQuery.java @@ -6,7 +6,10 @@ package org.hibernate.reactive.query.spi; import java.lang.invoke.MethodHandles; -import java.util.*; +import java.util.HashSet; +import java.util.List; +import java.util.Optional; +import java.util.Set; import java.util.concurrent.CompletionException; import java.util.concurrent.CompletionStage; import java.util.function.Consumer; @@ -30,12 +33,14 @@ import org.hibernate.query.sqm.internal.SqmInterpretationsKey.InterpretationsKeySource; import org.hibernate.query.sqm.tree.SqmStatement; import org.hibernate.query.sqm.tree.select.SqmSelectStatement; +import org.hibernate.reactive.engine.impl.ReactiveCallbackImpl; import org.hibernate.reactive.logging.impl.Log; import org.hibernate.reactive.logging.impl.LoggerFactory; import org.hibernate.reactive.query.sqm.internal.AggregatedSelectReactiveQueryPlan; import org.hibernate.reactive.query.sqm.internal.ConcreteSqmSelectReactiveQueryPlan; import org.hibernate.reactive.query.sqm.spi.ReactiveSelectQueryPlan; import org.hibernate.reactive.sql.results.spi.ReactiveSingleResultConsumer; +import org.hibernate.sql.exec.spi.Callback; import org.hibernate.sql.results.internal.TupleMetadata; import jakarta.persistence.NoResultException; @@ -76,6 +81,8 @@ public class ReactiveAbstractSelectionQuery { private final Function, R> uniqueElement; private final InterpretationsKeySource interpretationsKeySource; + private Callback callback; + // I'm sure we can avoid some of this by making some methods public in ORM, // but this allows me to prototype faster. We can refactor the code later. public ReactiveAbstractSelectionQuery( @@ -363,4 +370,11 @@ public void enableFetchProfile(String profileName) { } fetchProfiles.add( profileName ); } + + public Callback getCallback() { + if ( callback == null ) { + callback = new ReactiveCallbackImpl(); + } + return callback; + } } diff --git a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/query/sql/internal/ReactiveNativeQueryImpl.java b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/query/sql/internal/ReactiveNativeQueryImpl.java index bd38d53d4..6d162882a 100644 --- a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/query/sql/internal/ReactiveNativeQueryImpl.java +++ b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/query/sql/internal/ReactiveNativeQueryImpl.java @@ -46,6 +46,7 @@ import org.hibernate.reactive.query.sql.spi.ReactiveNativeQueryImplementor; import org.hibernate.reactive.query.sql.spi.ReactiveNonSelectQueryPlan; import org.hibernate.reactive.query.sqm.spi.ReactiveSelectQueryPlan; +import org.hibernate.sql.exec.spi.Callback; import org.hibernate.type.BasicTypeReference; import jakarta.persistence.AttributeConverter; @@ -192,6 +193,11 @@ public R getSingleResultOrNull() { return selectionQueryDelegate.getSingleResultOrNull(); } + @Override + public Callback getCallback() { + return selectionQueryDelegate.getCallback(); + } + @Override public CompletionStage getReactiveSingleResultOrNull() { return selectionQueryDelegate.getReactiveSingleResultOrNull(); diff --git a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/query/sqm/internal/ConcreteSqmSelectReactiveQueryPlan.java b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/query/sqm/internal/ConcreteSqmSelectReactiveQueryPlan.java index 01ee41c90..7c7cfd062 100644 --- a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/query/sqm/internal/ConcreteSqmSelectReactiveQueryPlan.java +++ b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/query/sqm/internal/ConcreteSqmSelectReactiveQueryPlan.java @@ -261,7 +261,7 @@ private static CacheableSqmInterpretation buildCacheableSqmInterpretation( domainParameterXref, executionContext.getQueryParameterBindings(), executionContext.getSession().getLoadQueryInfluencers(), - sessionFactory, + sessionFactory.getSqlTranslationEngine(), true ); diff --git a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/query/sqm/internal/ReactiveQuerySqmImpl.java b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/query/sqm/internal/ReactiveQuerySqmImpl.java index 4e9e8f001..096196576 100644 --- a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/query/sqm/internal/ReactiveQuerySqmImpl.java +++ b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/query/sqm/internal/ReactiveQuerySqmImpl.java @@ -61,6 +61,7 @@ import org.hibernate.reactive.query.sqm.mutation.spi.ReactiveSqmMultiTableMutationStrategy; import org.hibernate.reactive.query.sqm.spi.ReactiveSelectQueryPlan; import org.hibernate.reactive.session.ReactiveSqmQueryImplementor; +import org.hibernate.sql.exec.spi.Callback; import org.hibernate.transform.ResultTransformer; import jakarta.persistence.CacheRetrieveMode; @@ -174,6 +175,11 @@ public R getSingleResultOrNull() { return selectionQueryDelegate.getSingleResultOrNull(); } + @Override + public Callback getCallback() { + return selectionQueryDelegate.getCallback(); + } + @Override public R uniqueResult() { return selectionQueryDelegate.uniqueResult(); diff --git a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/query/sqm/internal/ReactiveSimpleDeleteQueryPlan.java b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/query/sqm/internal/ReactiveSimpleDeleteQueryPlan.java index 43271d29e..a17d1eb73 100644 --- a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/query/sqm/internal/ReactiveSimpleDeleteQueryPlan.java +++ b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/query/sqm/internal/ReactiveSimpleDeleteQueryPlan.java @@ -82,7 +82,7 @@ protected SqlAstTranslator createTranslato domainParameterXref, executionContext.getQueryParameterBindings(), executionContext.getSession().getLoadQueryInfluencers(), - factory + factory.getSqlTranslationEngine() ); sqmInterpretation = (SqmTranslation) translator.translate(); diff --git a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/query/sqm/internal/ReactiveSimpleInsertQueryPlan.java b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/query/sqm/internal/ReactiveSimpleInsertQueryPlan.java index 9d76895b7..bf67d16ea 100644 --- a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/query/sqm/internal/ReactiveSimpleInsertQueryPlan.java +++ b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/query/sqm/internal/ReactiveSimpleInsertQueryPlan.java @@ -102,7 +102,7 @@ private SqlAstTranslator createInsertTrans domainParameterXref, executionContext.getQueryParameterBindings(), executionContext.getSession().getLoadQueryInfluencers(), - factory + factory.getSqlTranslationEngine() ) .translate(); diff --git a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/query/sqm/internal/ReactiveSimpleUpdateQueryPlan.java b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/query/sqm/internal/ReactiveSimpleUpdateQueryPlan.java index 962149b5b..f49f848f5 100644 --- a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/query/sqm/internal/ReactiveSimpleUpdateQueryPlan.java +++ b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/query/sqm/internal/ReactiveSimpleUpdateQueryPlan.java @@ -103,7 +103,7 @@ private SqlAstTranslator createUpdateTrans domainParameterXref, executionContext.getQueryParameterBindings(), executionContext.getSession().getLoadQueryInfluencers(), - factory + factory.getSqlTranslationEngine() ); final SqmTranslation sqmInterpretation = translator.translate(); diff --git a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/query/sqm/internal/ReactiveSqmSelectionQueryImpl.java b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/query/sqm/internal/ReactiveSqmSelectionQueryImpl.java index d24ecb2db..bca5e2a65 100644 --- a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/query/sqm/internal/ReactiveSqmSelectionQueryImpl.java +++ b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/query/sqm/internal/ReactiveSqmSelectionQueryImpl.java @@ -39,6 +39,7 @@ import org.hibernate.query.sqm.tree.select.SqmSelectStatement; import org.hibernate.reactive.query.spi.ReactiveAbstractSelectionQuery; import org.hibernate.reactive.query.sqm.ReactiveSqmSelectionQuery; +import org.hibernate.sql.exec.spi.Callback; import jakarta.persistence.CacheRetrieveMode; import jakarta.persistence.CacheStoreMode; @@ -218,6 +219,11 @@ public CompletionStage getReactiveResultCount() { .getReactiveResultsCount( getSqmStatement().createCountQuery(), this ); } + @Override + public Callback getCallback() { + return selectionQueryDelegate.getCallback(); + } + @Override public List getResultList() { return selectionQueryDelegate.getResultList(); diff --git a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/query/sqm/mutation/internal/cte/ReactiveAbstractCteMutationHandler.java b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/query/sqm/mutation/internal/cte/ReactiveAbstractCteMutationHandler.java index 74f278fe7..20d0e31c5 100644 --- a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/query/sqm/mutation/internal/cte/ReactiveAbstractCteMutationHandler.java +++ b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/query/sqm/mutation/internal/cte/ReactiveAbstractCteMutationHandler.java @@ -96,7 +96,7 @@ default CompletionStage reactiveExecute(DomainQueryExecutionContext exe executionContext.getQueryOptions(), executionContext.getSession().getLoadQueryInfluencers(), executionContext.getQueryParameterBindings(), - factory + factory.getSqlTranslationEngine() ); final Map, List> parameterResolutions; if ( getDomainParameterXref().getSqmParameterCount() == 0 ) { diff --git a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/query/sqm/mutation/internal/cte/ReactiveCteInsertHandler.java b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/query/sqm/mutation/internal/cte/ReactiveCteInsertHandler.java index 5a4b1c5af..1e063f287 100644 --- a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/query/sqm/mutation/internal/cte/ReactiveCteInsertHandler.java +++ b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/query/sqm/mutation/internal/cte/ReactiveCteInsertHandler.java @@ -83,12 +83,15 @@ public class ReactiveCteInsertHandler extends CteInsertHandler implements Reacti private static final Log LOG = LoggerFactory.make( Log.class, MethodHandles.lookup() ); + private final SessionFactoryImplementor sessionFactory; + public ReactiveCteInsertHandler( CteTable cteTable, SqmInsertStatement sqmStatement, DomainParameterXref domainParameterXref, SessionFactoryImplementor sessionFactory) { super( cteTable, sqmStatement, domainParameterXref, sessionFactory ); + this.sessionFactory = sessionFactory; } @Override @@ -120,7 +123,7 @@ public CompletionStage reactiveExecute(DomainQueryExecutionContext exec executionContext.getQueryOptions(), executionContext.getSession().getLoadQueryInfluencers(), executionContext.getQueryParameterBindings(), - factory + factory.getSqlTranslationEngine() ); final TableGroup insertingTableGroup = sqmConverter.getMutatingTableGroup(); @@ -182,7 +185,7 @@ public CompletionStage reactiveExecute(DomainQueryExecutionContext exec querySpec -> { // This returns true if the insertion target uses a sequence with an optimizer // in which case we will fill the row_number column instead of the id column - if ( additionalInsertValues.applySelections( querySpec, getSessionFactory() ) ) { + if ( additionalInsertValues.applySelections( querySpec, sessionFactory ) ) { final CteColumn rowNumberColumn = getCteTable().getCteColumns() .get( getCteTable().getCteColumns().size() - 1 ); final ColumnReference columnReference = new ColumnReference( @@ -207,7 +210,7 @@ public CompletionStage reactiveExecute(DomainQueryExecutionContext exec 0, SqmInsertStrategyHelper.createRowNumberingExpression( querySpec, - getSessionFactory() + sessionFactory ) ) ); @@ -342,7 +345,7 @@ public CompletionStage reactiveExecute(DomainQueryExecutionContext exec ); final String fragment = ( (BulkInsertionCapableIdentifierGenerator) entityDescriptor.getGenerator() ) .determineBulkInsertionIdentifierGenerationSelectFragment( - getSessionFactory().getSqlStringGenerationContext() + sessionFactory.getSqlStringGenerationContext() ); rowsWithSequenceQuery.getSelectClause().addSqlSelection( new SqlSelectionImpl( diff --git a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/query/sqm/mutation/internal/temptable/ReactiveRestrictedDeleteExecutionDelegate.java b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/query/sqm/mutation/internal/temptable/ReactiveRestrictedDeleteExecutionDelegate.java index dc2a833c4..0e1097b63 100644 --- a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/query/sqm/mutation/internal/temptable/ReactiveRestrictedDeleteExecutionDelegate.java +++ b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/query/sqm/mutation/internal/temptable/ReactiveRestrictedDeleteExecutionDelegate.java @@ -117,7 +117,7 @@ public ReactiveRestrictedDeleteExecutionDelegate( queryOptions, loadQueryInfluencers, queryParameterBindings, - sessionFactory + sessionFactory.getSqlTranslationEngine() ); } diff --git a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/session/ReactiveSession.java b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/session/ReactiveSession.java index 94b95318f..f53ed4fca 100644 --- a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/session/ReactiveSession.java +++ b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/session/ReactiveSession.java @@ -78,6 +78,8 @@ public interface ReactiveSession extends ReactiveQueryProducer, ReactiveSharedSe CompletionStage reactiveLock(Object entity, LockOptions lockMode); + CompletionStage reactiveLock(String entityName, Object entity, LockOptions lockMode); + CompletionStage reactiveGet(Class entityClass, Object id); CompletionStage reactiveFind(Class entityClass, Object id, LockOptions lockOptions, EntityGraph fetchGraph); diff --git a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/session/impl/ReactiveSessionImpl.java b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/session/impl/ReactiveSessionImpl.java index c746c9547..52aeb7f4c 100644 --- a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/session/impl/ReactiveSessionImpl.java +++ b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/session/impl/ReactiveSessionImpl.java @@ -28,7 +28,7 @@ import org.hibernate.bytecode.enhance.spi.interceptor.EnhancementAsProxyLazinessInterceptor; import org.hibernate.collection.spi.PersistentCollection; import org.hibernate.dialect.Dialect; -import org.hibernate.engine.internal.StatefulPersistenceContext; +import org.hibernate.engine.internal.ReactivePersistenceContextAdapter; import org.hibernate.engine.spi.EffectiveEntityGraph; import org.hibernate.engine.spi.EntityEntry; import org.hibernate.engine.spi.EntityKey; @@ -55,7 +55,6 @@ import org.hibernate.event.spi.PersistEvent; import org.hibernate.event.spi.RefreshContext; import org.hibernate.event.spi.RefreshEvent; -import org.hibernate.event.spi.ResolveNaturalIdEvent; import org.hibernate.graph.GraphSemantic; import org.hibernate.graph.RootGraph; import org.hibernate.graph.spi.RootGraphImplementor; @@ -63,7 +62,11 @@ import org.hibernate.internal.SessionFactoryImpl; import org.hibernate.internal.SessionImpl; import org.hibernate.jpa.spi.NativeQueryTupleTransformer; +import org.hibernate.loader.LoaderLogging; import org.hibernate.loader.ast.spi.MultiIdLoadOptions; +import org.hibernate.loader.internal.LoadAccessContext; +import org.hibernate.metamodel.mapping.EntityMappingType; +import org.hibernate.metamodel.mapping.NaturalIdMapping; import org.hibernate.persister.entity.EntityPersister; import org.hibernate.pretty.MessageHelper; import org.hibernate.proxy.HibernateProxy; @@ -87,7 +90,6 @@ import org.hibernate.reactive.common.InternalStateAssertions; import org.hibernate.reactive.common.ResultSetMapping; import org.hibernate.reactive.engine.ReactiveActionQueue; -import org.hibernate.reactive.engine.impl.ReactivePersistenceContextAdapter; import org.hibernate.reactive.event.ReactiveDeleteEventListener; import org.hibernate.reactive.event.ReactiveFlushEventListener; import org.hibernate.reactive.event.ReactiveLoadEventListener; @@ -95,9 +97,9 @@ import org.hibernate.reactive.event.ReactiveMergeEventListener; import org.hibernate.reactive.event.ReactivePersistEventListener; import org.hibernate.reactive.event.ReactiveRefreshEventListener; -import org.hibernate.reactive.event.ReactiveResolveNaturalIdEventListener; import org.hibernate.reactive.event.impl.DefaultReactiveAutoFlushEventListener; import org.hibernate.reactive.event.impl.DefaultReactiveInitializeCollectionEventListener; +import org.hibernate.reactive.loader.ast.spi.ReactiveNaturalIdLoader; import org.hibernate.reactive.logging.impl.Log; import org.hibernate.reactive.logging.impl.LoggerFactory; import org.hibernate.reactive.persister.entity.impl.ReactiveEntityPersister; @@ -186,8 +188,8 @@ private void threadCheck() { } @Override - protected StatefulPersistenceContext createPersistenceContext() { - return new ReactivePersistenceContextAdapter( this ); + protected PersistenceContext createPersistenceContext() { + return new ReactivePersistenceContextAdapter( super.createPersistenceContext() ); } @Override @@ -691,7 +693,7 @@ public CompletionStage reactiveInitializeCollection(PersistentCollection eventListenerGroupInitCollection = fastSessionServices.eventListenerGroup_INIT_COLLECTION; + EventListenerGroup eventListenerGroupInitCollection = getFactory().getEventListenerGroups().eventListenerGroup_INIT_COLLECTION; return eventListenerGroupInitCollection .fireEventOnEachListener( event, @@ -732,7 +734,7 @@ private CompletionStage firePersist(PersistEvent event) { checkTransactionSynchStatus(); checkNoUnresolvedActionsBeforeOperation(); - return fastSessionServices.eventListenerGroup_PERSIST + return getFactory().getEventListenerGroups().eventListenerGroup_PERSIST .fireEventOnEachListener( event, (ReactivePersistEventListener l) -> l::reactiveOnPersist ) .handle( (v, e) -> { checkNoUnresolvedActionsAfterOperation(); @@ -750,7 +752,7 @@ else if ( e instanceof RuntimeException ) { private CompletionStage firePersist(PersistContext copiedAlready, PersistEvent event) { pulseTransactionCoordinator(); - return fastSessionServices.eventListenerGroup_PERSIST + return getFactory().getEventListenerGroups().eventListenerGroup_PERSIST .fireEventOnEachListener( event, copiedAlready, (ReactivePersistEventListener l) -> l::reactiveOnPersist ) .handle( (v, e) -> { delayedAfterCompletion(); @@ -774,7 +776,7 @@ public CompletionStage reactivePersistOnFlush(Object entity, PersistContex private CompletionStage firePersistOnFlush(PersistContext copiedAlready, PersistEvent event) { pulseTransactionCoordinator(); - return fastSessionServices.eventListenerGroup_PERSIST + return getFactory().getEventListenerGroups().eventListenerGroup_PERSIST .fireEventOnEachListener( event, copiedAlready, (ReactivePersistEventListener l) -> l::reactiveOnPersist ) .whenComplete( (v, e) -> delayedAfterCompletion() ); } @@ -802,13 +804,13 @@ public CompletionStage reactiveRemove( boolean isCascadeDeleteEnabled, DeleteContext transientEntities) { checkOpenOrWaitingForAutoClose(); - final boolean removingOrphanBeforeUpates = persistenceContext().isRemovingOrphanBeforeUpates(); - if ( LOG.isTraceEnabled() && removingOrphanBeforeUpates ) { + final boolean removingOrphanBeforeUpdates = persistenceContext().isRemovingOrphanBeforeUpdates(); + if ( LOG.isTraceEnabled() && removingOrphanBeforeUpdates ) { logRemoveOrphanBeforeUpdates( "before continuing", entityName, entityName ); } return fireRemove( - new DeleteEvent( entityName, child, isCascadeDeleteEnabled, removingOrphanBeforeUpates, this ), + new DeleteEvent( entityName, child, isCascadeDeleteEnabled, removingOrphanBeforeUpdates, this ), transientEntities ); } @@ -830,10 +832,8 @@ private void logRemoveOrphanBeforeUpdates(String timing, String entityName, Obje private CompletionStage fireRemove(DeleteEvent event) { pulseTransactionCoordinator(); - return fastSessionServices.eventListenerGroup_DELETE.fireEventOnEachListener( - event, - (ReactiveDeleteEventListener l) -> l::reactiveOnDelete - ) + return getFactory().getEventListenerGroups().eventListenerGroup_DELETE + .fireEventOnEachListener( event, (ReactiveDeleteEventListener l) -> l::reactiveOnDelete ) .handle( (v, e) -> { delayedAfterCompletion(); @@ -854,9 +854,8 @@ else if ( e instanceof RuntimeException ) { private CompletionStage fireRemove(DeleteEvent event, DeleteContext transientEntities) { pulseTransactionCoordinator(); - return fastSessionServices.eventListenerGroup_DELETE.fireEventOnEachListener( event, transientEntities, - (ReactiveDeleteEventListener l) -> l::reactiveOnDelete - ) + return getFactory().getEventListenerGroups().eventListenerGroup_DELETE + .fireEventOnEachListener( event, transientEntities, (ReactiveDeleteEventListener l) -> l::reactiveOnDelete ) .handle( (v, e) -> { delayedAfterCompletion(); @@ -892,7 +891,7 @@ private CompletionStage fireMerge(MergeEvent event) { checkTransactionSynchStatus(); checkNoUnresolvedActionsBeforeOperation(); - return fastSessionServices.eventListenerGroup_MERGE + return getFactory().getEventListenerGroups().eventListenerGroup_MERGE .fireEventOnEachListener( event, (ReactiveMergeEventListener l) -> l::reactiveOnMerge ) .handle( (v, e) -> { checkNoUnresolvedActionsAfterOperation(); @@ -914,7 +913,7 @@ else if ( e instanceof RuntimeException ) { private CompletionStage fireMerge(MergeContext copiedAlready, MergeEvent event) { pulseTransactionCoordinator(); - return fastSessionServices.eventListenerGroup_MERGE + return getFactory().getEventListenerGroups().eventListenerGroup_MERGE .fireEventOnEachListener( event, copiedAlready,(ReactiveMergeEventListener l) -> l::reactiveOnMerge ) .handle( (v, e) -> { delayedAfterCompletion(); @@ -954,7 +953,7 @@ public CompletionStage reactiveAutoFlushIfRequired(Set querySpa // } AutoFlushEvent event = new AutoFlushEvent( querySpaces, this ); - return fastSessionServices.eventListenerGroup_AUTO_FLUSH + return getFactory().getEventListenerGroups().eventListenerGroup_AUTO_FLUSH .fireEventOnEachListener( event, (DefaultReactiveAutoFlushEventListener l) -> l::reactiveOnAutoFlush ) .thenApply( v -> event.isFlushRequired() ); } @@ -987,7 +986,7 @@ private CompletionStage doFlush() { throw LOG.flushDuringCascadeIsDangerous(); } - return fastSessionServices.eventListenerGroup_FLUSH + return getFactory().getEventListenerGroups().eventListenerGroup_FLUSH .fireEventOnEachListener( new FlushEvent( this ), (ReactiveFlushEventListener l) -> l::reactiveOnFlush ) .handle( (v, e) -> { delayedAfterCompletion(); @@ -1036,10 +1035,8 @@ CompletionStage fireRefresh(RefreshEvent event) { } pulseTransactionCoordinator(); - return fastSessionServices.eventListenerGroup_REFRESH.fireEventOnEachListener( - event, - (ReactiveRefreshEventListener l) -> l::reactiveOnRefresh - ) + return getFactory().getEventListenerGroups().eventListenerGroup_REFRESH + .fireEventOnEachListener( event, (ReactiveRefreshEventListener l) -> l::reactiveOnRefresh ) .handle( (v, e) -> { delayedAfterCompletion(); @@ -1059,12 +1056,8 @@ CompletionStage fireRefresh(RefreshEvent event) { private CompletionStage fireRefresh(RefreshContext refreshedAlready, RefreshEvent event) { pulseTransactionCoordinator(); - return fastSessionServices.eventListenerGroup_REFRESH - .fireEventOnEachListener( - event, - refreshedAlready, - (ReactiveRefreshEventListener l) -> l::reactiveOnRefresh - ) + return getFactory().getEventListenerGroups().eventListenerGroup_REFRESH + .fireEventOnEachListener( event, refreshedAlready, (ReactiveRefreshEventListener l) -> l::reactiveOnRefresh ) .handle( (v, e) -> { delayedAfterCompletion(); @@ -1081,13 +1074,17 @@ public CompletionStage reactiveLock(Object object, LockOptions lockOptions return fireLock( new LockEvent( object, lockOptions, this ) ); } + @Override + public CompletionStage reactiveLock(String entityName, Object object, LockOptions lockOptions) { + checkOpen(); + return fireLock( new LockEvent( entityName, object, lockOptions, this ) ); + } + private CompletionStage fireLock(LockEvent event) { pulseTransactionCoordinator(); - return fastSessionServices.eventListenerGroup_LOCK.fireEventOnEachListener( - event, - (ReactiveLockEventListener l) -> l::reactiveOnLock - ) + return getFactory().getEventListenerGroups().eventListenerGroup_LOCK + .fireEventOnEachListener( event, (ReactiveLockEventListener l) -> l::reactiveOnLock ) .handle( (v, e) -> { delayedAfterCompletion(); @@ -1175,11 +1172,21 @@ public CompletionStage> reactiveFind(Class entityClass, Object... @Override public CompletionStage reactiveFind(Class entityClass, Map ids) { - final EntityPersister persister = getFactory().getMappingMetamodel().getEntityDescriptor( entityClass ); - return new NaturalIdLoadAccessImpl( persister ).resolveNaturalId( ids ) + final ReactiveEntityPersister persister = entityPersister( entityClass ); + final Object normalizedIdValues = persister.getNaturalIdMapping().normalizeInput( ids ); + return new NaturalIdLoadAccessImpl( this, persister, requireEntityPersister( entityClass ) ) + .resolveNaturalId( normalizedIdValues ) .thenCompose( id -> reactiveFind( entityClass, id, null, null ) ); } + private ReactiveEntityPersister entityPersister(Class entityClass) { + return (ReactiveEntityPersister) getFactory().getMappingMetamodel().getEntityDescriptor( entityClass ); + } + + private EntityPersister requireEntityPersister(Class entityClass) { + return getFactory().getMappingMetamodel().getEntityDescriptor( entityClass ); + } + private CompletionStage fireReactiveLoad(LoadEvent event, LoadEventListener.LoadType loadType) { checkOpenOrWaitingForAutoClose(); @@ -1190,20 +1197,11 @@ private CompletionStage fireReactiveLoad(LoadEvent event, LoadEventListene private CompletionStage fireLoadNoChecks(LoadEvent event, LoadEventListener.LoadType loadType) { pulseTransactionCoordinator(); - return fastSessionServices.eventListenerGroup_LOAD + return getFactory().getEventListenerGroups().eventListenerGroup_LOAD .fireEventOnEachListener( event, loadType,(ReactiveLoadEventListener l) -> l::reactiveOnLoad ); } - private CompletionStage fireResolveNaturalId(ResolveNaturalIdEvent event) { - checkOpenOrWaitingForAutoClose(); - return fastSessionServices.eventListenerGroup_RESOLVE_NATURAL_ID.fireEventOnEachListener( - event, - (ReactiveResolveNaturalIdEventListener l) -> l::onReactiveResolveNaturalId - ) - .whenComplete( (c, e) -> delayedAfterCompletion() ); - } - @Override public void delayedAfterCompletion() { //disable for now, but figure out what to do here @@ -1472,8 +1470,7 @@ public CompletionStage> multiLoad(Object... ids) { Object[] sids = new Object[ids.length]; System.arraycopy( ids, 0, sids, 0, ids.length ); - return perform( () -> (CompletionStage) - ( (ReactiveEntityPersister) entityPersister ) + return perform( () -> (CompletionStage) ( (ReactiveEntityPersister) entityPersister ) .reactiveMultiLoad( sids, ReactiveSessionImpl.this, this ) ); } @@ -1517,12 +1514,16 @@ public CompletionStage> multiLoad(List ids) { } private class NaturalIdLoadAccessImpl { - private final EntityPersister entityPersister; + private final LoadAccessContext context; + private final ReactiveEntityPersister entityPersister; + private final EntityMappingType entityDescriptor; private LockOptions lockOptions; private boolean synchronizationEnabled = true; - private NaturalIdLoadAccessImpl(EntityPersister entityPersister) { + private NaturalIdLoadAccessImpl(LoadAccessContext context, ReactiveEntityPersister entityPersister, EntityMappingType entityDescriptor) { + this.context = context; this.entityPersister = entityPersister; + this.entityDescriptor = entityDescriptor; if ( !entityPersister.hasNaturalIdentifier() ) { throw LOG.entityDidNotDefinedNaturalId( entityPersister.getEntityName() ); @@ -1538,13 +1539,35 @@ protected void synchronizationEnabled(boolean synchronizationEnabled) { this.synchronizationEnabled = synchronizationEnabled; } - protected final CompletionStage resolveNaturalId(Map naturalIdParameters) { + /** + * @see org.hibernate.loader.internal.BaseNaturalIdLoadAccessImpl#doGetReference(Object) + */ + protected final CompletionStage resolveNaturalId(Object normalizedNaturalIdValue) { performAnyNeededCrossReferenceSynchronizations(); - ResolveNaturalIdEvent event = - new ResolveNaturalIdEvent( naturalIdParameters, entityPersister, ReactiveSessionImpl.this ); - return fireResolveNaturalId( event ) - .thenApply( v -> event.getEntityId() == INVALID_NATURAL_ID_REFERENCE ? null : event.getEntityId() ); + context.checkOpenOrWaitingForAutoClose(); + context.pulseTransactionCoordinator(); + + final SessionImplementor session = getSession(); + final PersistenceContext persistenceContext = session.getPersistenceContextInternal(); + final Object cachedResolution = persistenceContext.getNaturalIdResolutions() + .findCachedIdByNaturalId( normalizedNaturalIdValue, entityPersister() ); + if ( cachedResolution == INVALID_NATURAL_ID_REFERENCE ) { + // the entity is deleted, although not yet flushed - return null + return nullFuture(); + } + else if ( cachedResolution != null ) { + return completedFuture( cachedResolution ); + } + else { + LoaderLogging.LOADER_LOGGER.debugf( + "Selecting entity identifier by natural-id for `#getReference` handling - %s : %s", + entityPersister().getEntityName(), + normalizedNaturalIdValue + ); + return ( (ReactiveNaturalIdLoader) entityPersister().getNaturalIdLoader() ) + .resolveNaturalIdToId( normalizedNaturalIdValue, session ); + } } protected void performAnyNeededCrossReferenceSynchronizations() { @@ -1552,7 +1575,9 @@ protected void performAnyNeededCrossReferenceSynchronizations() { // synchronization (this process) was disabled return; } - if ( entityPersister.getEntityMetamodel().hasImmutableNaturalId() ) { + + final NaturalIdMapping naturalIdMapping = entityDescriptor.getNaturalIdMapping(); + if ( !naturalIdMapping.isMutable() ) { // only mutable natural-ids need this processing return; } @@ -1562,7 +1587,7 @@ protected void performAnyNeededCrossReferenceSynchronizations() { } final PersistenceContext persistenceContext = getPersistenceContextInternal(); -// final boolean debugEnabled = log.isDebugEnabled(); + final boolean loggerDebugEnabled = LoaderLogging.LOADER_LOGGER.isDebugEnabled(); for ( Object pk : persistenceContext.getNaturalIdResolutions() .getCachedPkResolutions( entityPersister ) ) { final EntityKey entityKey = generateEntityKey( pk, entityPersister ); @@ -1570,12 +1595,13 @@ protected void performAnyNeededCrossReferenceSynchronizations() { final EntityEntry entry = persistenceContext.getEntry( entity ); if ( entry == null ) { -// if ( debugEnabled ) { -// log.debug( -// "Cached natural-id/pk resolution linked to null EntityEntry in persistence context : " -// + MessageHelper.infoString( entityPersister, pk, getFactory() ) -// ); -// } + if ( loggerDebugEnabled ) { + LoaderLogging.LOADER_LOGGER.debugf( + "Cached natural-id/pk resolution linked to null EntityEntry in persistence context : %s#%s", + entityDescriptor.getEntityName(), + pk + ); + } continue; } @@ -1588,21 +1614,19 @@ protected void performAnyNeededCrossReferenceSynchronizations() { continue; } - persistenceContext.getNaturalIdResolutions() - .handleSynchronization( pk, entity, entityPersister ); + persistenceContext.getNaturalIdResolutions().handleSynchronization( pk, entity, entityPersister() ); } } protected final ReactiveIdentifierLoadAccessImpl getIdentifierLoadAccess() { - final ReactiveIdentifierLoadAccessImpl identifierLoadAccess = new ReactiveIdentifierLoadAccessImpl<>( - entityPersister ); + final ReactiveIdentifierLoadAccessImpl identifierLoadAccess = new ReactiveIdentifierLoadAccessImpl<>( entityPersister ); if ( this.lockOptions != null ) { identifierLoadAccess.with( lockOptions ); } return identifierLoadAccess; } - protected EntityPersister entityPersister() { + protected ReactiveEntityPersister entityPersister() { return entityPersister; } } @@ -1688,7 +1712,7 @@ public void removeOrphanBeforeUpdates(String entityName, Object child) { public CompletionStage reactiveRemoveOrphanBeforeUpdates(String entityName, Object child) { // TODO: The removeOrphan concept is a temporary "hack" for HHH-6484. This should be removed once action/task // ordering is improved. - final StatefulPersistenceContext persistenceContext = (StatefulPersistenceContext) getPersistenceContextInternal(); + final PersistenceContext persistenceContext = getPersistenceContextInternal(); persistenceContext.beginRemoveOrphanBeforeUpdates(); return fireRemove( new DeleteEvent( entityName, child, false, true, this ) ) .thenAccept( v -> { @@ -1709,7 +1733,7 @@ private void logRemoveOrphanBeforeUpdates( String timing, String entityName, Object entity, - StatefulPersistenceContext persistenceContext) { + PersistenceContext persistenceContext) { if ( LOG.isTraceEnabled() ) { final EntityEntry entityEntry = persistenceContext.getEntry( entity ); LOG.tracef( diff --git a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/session/impl/ReactiveStatelessSessionImpl.java b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/session/impl/ReactiveStatelessSessionImpl.java index 5e02b9389..dd83e983e 100644 --- a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/session/impl/ReactiveStatelessSessionImpl.java +++ b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/session/impl/ReactiveStatelessSessionImpl.java @@ -62,7 +62,7 @@ import org.hibernate.query.sqm.tree.update.SqmUpdateStatement; import org.hibernate.reactive.common.AffectedEntities; import org.hibernate.reactive.common.ResultSetMapping; -import org.hibernate.reactive.engine.impl.ReactivePersistenceContextAdapter; +import org.hibernate.engine.internal.ReactivePersistenceContextAdapter; import org.hibernate.reactive.id.ReactiveIdentifierGenerator; import org.hibernate.reactive.logging.impl.Log; import org.hibernate.reactive.persister.collection.impl.ReactiveCollectionPersister; @@ -133,7 +133,7 @@ public class ReactiveStatelessSessionImpl extends StatelessSessionImpl implement public ReactiveStatelessSessionImpl(SessionFactoryImpl factory, SessionCreationOptions options, ReactiveConnection connection) { super( factory, options ); reactiveConnection = connection; - persistenceContext = new ReactivePersistenceContextAdapter( this ); + persistenceContext = new ReactivePersistenceContextAdapter( super.getPersistenceContext() ); batchingHelperSession = new ReactiveStatelessSessionImpl( factory, options, reactiveConnection, persistenceContext ); influencers = new LoadQueryInfluencers( factory ); } @@ -315,13 +315,13 @@ private CompletionStage reactiveInsert(Object entity, ReactiveEntityPersis } private boolean firePreInsert(Object entity, Object id, Object[] state, EntityPersister persister) { - if ( fastSessionServices.eventListenerGroup_PRE_INSERT.isEmpty() ) { + if ( getFactory().getEventListenerGroups().eventListenerGroup_PRE_INSERT.isEmpty() ) { return false; } else { boolean veto = false; final PreInsertEvent event = new PreInsertEvent( entity, id, state, persister, null ); - for ( PreInsertEventListener listener : fastSessionServices.eventListenerGroup_PRE_INSERT.listeners() ) { + for ( PreInsertEventListener listener : getFactory().getEventListenerGroups().eventListenerGroup_PRE_INSERT.listeners() ) { veto |= listener.onPreInsert( event ); } return veto; @@ -329,9 +329,9 @@ private boolean firePreInsert(Object entity, Object id, Object[] state, EntityPe } private void firePostInsert(Object entity, Object id, Object[] state, EntityPersister persister) { - if ( !fastSessionServices.eventListenerGroup_POST_INSERT.isEmpty() ) { + if ( !getFactory().getEventListenerGroups().eventListenerGroup_POST_INSERT.isEmpty() ) { final PostInsertEvent event = new PostInsertEvent( entity, id, state, persister, null ); - for ( PostInsertEventListener listener : fastSessionServices.eventListenerGroup_POST_INSERT.listeners() ) { + for ( PostInsertEventListener listener : getFactory().getEventListenerGroups().eventListenerGroup_POST_INSERT.listeners() ) { listener.onPostInsert( event ); } } diff --git a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/sql/exec/internal/ReactiveStandardMutationExecutorService.java b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/sql/exec/internal/ReactiveStandardMutationExecutorService.java index c02fc0551..46fffd02b 100644 --- a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/sql/exec/internal/ReactiveStandardMutationExecutorService.java +++ b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/sql/exec/internal/ReactiveStandardMutationExecutorService.java @@ -72,9 +72,8 @@ public MutationExecutor createExecutor( } private static GeneratedValuesMutationDelegate generatedValuesDelegate(MutationOperationGroup operationGroup) { - GeneratedValuesMutationDelegate generatedValuesMutationDelegate = operationGroup.asEntityMutationOperationGroup() != null + return operationGroup.asEntityMutationOperationGroup() != null ? operationGroup.asEntityMutationOperationGroup().getMutationDelegate() : null; - return generatedValuesMutationDelegate; } } diff --git a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/sql/exec/internal/StandardReactiveSelectExecutor.java b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/sql/exec/internal/StandardReactiveSelectExecutor.java index bcf33c942..43b7c1554 100644 --- a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/sql/exec/internal/StandardReactiveSelectExecutor.java +++ b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/sql/exec/internal/StandardReactiveSelectExecutor.java @@ -19,7 +19,7 @@ import org.hibernate.engine.spi.SharedSessionContractImplementor; import org.hibernate.internal.util.collections.ArrayHelper; import org.hibernate.query.TupleTransformer; -import org.hibernate.reactive.engine.impl.ReactivePersistenceContextAdapter; +import org.hibernate.engine.internal.ReactivePersistenceContextAdapter; import org.hibernate.reactive.sql.exec.spi.ReactiveRowProcessingState; import org.hibernate.reactive.sql.exec.spi.ReactiveSelectExecutor; import org.hibernate.reactive.sql.exec.spi.ReactiveValuesResultSet; diff --git a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/sql/results/graph/entity/internal/ReactiveEntityDelayedFetchInitializer.java b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/sql/results/graph/entity/internal/ReactiveEntityDelayedFetchInitializer.java index 1a1660725..c40ee20d3 100644 --- a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/sql/results/graph/entity/internal/ReactiveEntityDelayedFetchInitializer.java +++ b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/sql/results/graph/entity/internal/ReactiveEntityDelayedFetchInitializer.java @@ -131,7 +131,7 @@ public CompletionStage reactiveResolveInstance(EntityDelayedFetchInitializ final String uniqueKeyPropertyName = referencedModelPart.getReferencedPropertyName(); final Type uniqueKeyPropertyType = uniqueKeyPropertyName == null ? concreteDescriptor.getIdentifierType() - : session.getFactory().getReferencedPropertyType( concreteDescriptor.getEntityName(), uniqueKeyPropertyName ); + : session.getFactory().getRuntimeMetamodels().getReferencedPropertyType( concreteDescriptor.getEntityName(), uniqueKeyPropertyName ); final EntityUniqueKey euk = new EntityUniqueKey( concreteDescriptor.getEntityName(), uniqueKeyPropertyName, diff --git a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/sql/results/graph/entity/internal/ReactiveEntityInitializerImpl.java b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/sql/results/graph/entity/internal/ReactiveEntityInitializerImpl.java index a00287eab..8601d434f 100644 --- a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/sql/results/graph/entity/internal/ReactiveEntityInitializerImpl.java +++ b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/sql/results/graph/entity/internal/ReactiveEntityInitializerImpl.java @@ -20,7 +20,6 @@ import org.hibernate.engine.spi.PersistentAttributeInterceptor; import org.hibernate.engine.spi.SharedSessionContractImplementor; import org.hibernate.engine.spi.Status; -import org.hibernate.loader.ast.internal.CacheEntityLoaderHelper; import org.hibernate.metamodel.mapping.internal.ToOneAttributeMapping; import org.hibernate.persister.entity.EntityPersister; import org.hibernate.proxy.LazyInitializer; @@ -45,6 +44,7 @@ import static org.hibernate.bytecode.enhance.spi.LazyPropertyInitializer.UNFETCHED_PROPERTY; import static org.hibernate.engine.internal.ManagedTypeHelper.asPersistentAttributeInterceptable; import static org.hibernate.engine.internal.ManagedTypeHelper.isPersistentAttributeInterceptable; +import static org.hibernate.loader.internal.CacheLoadHelper.loadFromSecondLevelCache; import static org.hibernate.metamodel.mapping.ForeignKeyDescriptor.Nature.TARGET; import static org.hibernate.proxy.HibernateProxy.extractLazyInitializer; import static org.hibernate.reactive.util.impl.CompletionStages.completedFuture; @@ -576,7 +576,7 @@ private boolean isProxyInstance(Object proxy) { // FIXME: I could change the scope of this method in ORM private Object resolveInstanceFromCache(ReactiveEntityInitializerData data) { - return CacheEntityLoaderHelper.INSTANCE.loadFromSecondLevelCache( + return loadFromSecondLevelCache( data.getRowProcessingState().getSession().asEventSource(), null, data.getLockMode(), diff --git a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/sql/results/graph/entity/internal/ReactiveEntitySelectFetchInitializerBuilder.java b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/sql/results/graph/entity/internal/ReactiveEntitySelectFetchInitializerBuilder.java index c4cb87838..a3b7d46f1 100644 --- a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/sql/results/graph/entity/internal/ReactiveEntitySelectFetchInitializerBuilder.java +++ b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/sql/results/graph/entity/internal/ReactiveEntitySelectFetchInitializerBuilder.java @@ -100,7 +100,7 @@ public static EntityInitializer createInitializer( throw new IllegalStateException( "Should be unreachable" ); } - // FIXME: Use the one in ORM + // FIXME: Use the one in ORM: EntitySelectFetchInitializerBuilder#determineBatchMode public static BatchMode determineBatchMode( EntityPersister entityPersister, InitializerParent parent, diff --git a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/sql/results/internal/ReactiveDeferredResultSetAccess.java b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/sql/results/internal/ReactiveDeferredResultSetAccess.java index a6f7ed675..3f88bcffb 100644 --- a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/sql/results/internal/ReactiveDeferredResultSetAccess.java +++ b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/sql/results/internal/ReactiveDeferredResultSetAccess.java @@ -13,14 +13,17 @@ import java.util.concurrent.CompletionStage; import org.hibernate.HibernateException; +import org.hibernate.LockOptions; import org.hibernate.engine.jdbc.spi.SqlStatementLogger; import org.hibernate.engine.spi.SessionEventListenerManager; import org.hibernate.engine.spi.SessionFactoryImplementor; import org.hibernate.reactive.adaptor.impl.PreparedStatementAdaptor; +import org.hibernate.reactive.engine.impl.ReactiveCallbackImpl; import org.hibernate.reactive.logging.impl.Log; import org.hibernate.reactive.logging.impl.LoggerFactory; import org.hibernate.reactive.pool.ReactiveConnection; import org.hibernate.reactive.session.ReactiveConnectionSupplier; +import org.hibernate.reactive.session.ReactiveSession; import org.hibernate.reactive.util.impl.CompletionStages; import org.hibernate.resource.jdbc.spi.JdbcSessionContext; import org.hibernate.resource.jdbc.spi.LogicalConnectionImplementor; @@ -60,6 +63,22 @@ public ReactiveDeferredResultSetAccess( this.sqlStatementLogger = executionContext.getSession().getJdbcServices().getSqlStatementLogger(); } + /** + * Reactive version of {@link org.hibernate.sql.results.jdbc.internal.DeferredResultSetAccess#registerAfterLoadAction(ExecutionContext, LockOptions)} + * calling {@link ReactiveSession#reactiveLock(String, Object, LockOptions)} + */ + @Override + protected void registerAfterLoadAction(ExecutionContext executionContext, LockOptions lockOptionsToUse) { + ( (ReactiveCallbackImpl) executionContext.getCallback() ).registerReactiveAfterLoadAction( + (entity, persister, session) -> + ( (ReactiveSession) session ).reactiveLock( + persister.getEntityName(), + entity, + lockOptionsToUse + ) + ); + } + @Override public ResultSet getResultSet() { if ( resultSet == null ) { diff --git a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/sql/results/internal/ReactiveInitializersList.java b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/sql/results/internal/ReactiveInitializersList.java index 312f510f5..49c7deda4 100644 --- a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/sql/results/internal/ReactiveInitializersList.java +++ b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/sql/results/internal/ReactiveInitializersList.java @@ -87,7 +87,7 @@ ReactiveInitializersList build(final Map> initiali } private Initializer[] toArray(final ArrayList> initializers) { - return initializers.toArray( new Initializer[initializers.size()] ); + return initializers.toArray( new Initializer[0] ); } } } diff --git a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/sql/results/spi/ReactiveListResultsConsumer.java b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/sql/results/spi/ReactiveListResultsConsumer.java index 7c23bc739..aa75fdf6e 100644 --- a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/sql/results/spi/ReactiveListResultsConsumer.java +++ b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/sql/results/spi/ReactiveListResultsConsumer.java @@ -13,6 +13,7 @@ import java.util.function.Supplier; import org.hibernate.HibernateException; +import org.hibernate.engine.internal.ReactivePersistenceContextAdapter; import org.hibernate.engine.spi.PersistenceContext; import org.hibernate.engine.spi.SharedSessionContractImplementor; import org.hibernate.query.ResultListTransformer; @@ -103,7 +104,7 @@ public CompletionStage> consume( } return falseFuture(); } ) ) - .thenApply( v -> finishUp( rowReader, rowProcessingState, jdbcValuesSourceProcessingState, results, readRows, queryOptions ) ) + .thenCompose( v -> finishUp( rowReader, rowProcessingState, jdbcValuesSourceProcessingState, results, readRows, queryOptions ) ) .handle( CompletionStages::handle ) .thenCompose( handler -> { end( jdbcValues, session, jdbcValuesSourceProcessingState, persistenceContext, handler.getThrowable() ); @@ -111,20 +112,40 @@ public CompletionStage> consume( } ); } - private List finishUp( + private CompletionStage> finishUp( ReactiveRowReader rowReader, ReactiveRowProcessingState rowProcessingState, JdbcValuesSourceProcessingStateStandardImpl jdbcValuesSourceProcessingState, Results results, int[] readRows, QueryOptions queryOptions) { rowReader.finishUp( rowProcessingState ); - jdbcValuesSourceProcessingState.finishUp( readRows[0] > 1 ); + return finishUp( readRows[0] > 1, rowProcessingState.getSession(), jdbcValuesSourceProcessingState ) + .thenApply( v -> { + final ResultListTransformer resultListTransformer = (ResultListTransformer) queryOptions.getResultListTransformer(); + return resultListTransformer != null + ? resultListTransformer.transformList( results.getResults() ) + : results.getResults(); + } ); + } - final ResultListTransformer resultListTransformer = (ResultListTransformer) queryOptions.getResultListTransformer(); - return resultListTransformer != null - ? resultListTransformer.transformList( results.getResults() ) - : results.getResults(); + /** + * Reactive equivalent of {@link org.hibernate.sql.results.jdbc.internal.JdbcValuesSourceProcessingStateStandardImpl#finishUp(boolean)} + */ + private static CompletionStage finishUp( + boolean registerSubselects, + SharedSessionContractImplementor session, + JdbcValuesSourceProcessingStateStandardImpl jdbcValuesSourceProcessingState) { + jdbcValuesSourceProcessingState.finishLoadingCollections(); + + return ( (ReactivePersistenceContextAdapter) session.getPersistenceContextInternal() ) + .reactivePostLoad( + jdbcValuesSourceProcessingState, + registerSubselects ? + jdbcValuesSourceProcessingState.getExecutionContext()::registerLoadingEntityHolder : + null + ); } + /** * The boolean in the CompletionStage is true if the element has been added to the results */ @@ -284,8 +305,7 @@ public boolean addUnique(R result) { } public boolean add(R result) { - results.add( result ); - return true; + return results.add( result ); } public List getResults() { diff --git a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/sql/results/spi/ReactiveSingleResultConsumer.java b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/sql/results/spi/ReactiveSingleResultConsumer.java index 814db1e4b..6c44f88d7 100644 --- a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/sql/results/spi/ReactiveSingleResultConsumer.java +++ b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/sql/results/spi/ReactiveSingleResultConsumer.java @@ -8,6 +8,7 @@ import java.util.concurrent.CompletionStage; import org.hibernate.Incubating; +import org.hibernate.engine.internal.ReactivePersistenceContextAdapter; import org.hibernate.engine.spi.SharedSessionContractImplementor; import org.hibernate.reactive.sql.exec.spi.ReactiveRowProcessingState; import org.hibernate.reactive.sql.exec.spi.ReactiveValuesResultSet; @@ -29,11 +30,14 @@ public CompletionStage consume( return rowProcessingState.next() .thenCompose( hasNext -> rowReader .reactiveReadRow( rowProcessingState, processingOptions ) - .thenApply( result -> { + .thenCompose( result -> { rowProcessingState.finishRowProcessing( true ); rowReader.finishUp( rowProcessingState ); - jdbcValuesSourceProcessingState.finishUp( false ); - return result; + session.getPersistenceContext(); + jdbcValuesSourceProcessingState.finishLoadingCollections(); + return ( (ReactivePersistenceContextAdapter) session.getPersistenceContextInternal() ) + .reactivePostLoad( jdbcValuesSourceProcessingState, null ) + .thenApply( v -> result ); } ) ); } diff --git a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/type/descriptor/jdbc/ReactiveXmlJdbcType.java b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/type/descriptor/jdbc/ReactiveXmlJdbcType.java index 1362e3a20..3c3667aa3 100644 --- a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/type/descriptor/jdbc/ReactiveXmlJdbcType.java +++ b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/type/descriptor/jdbc/ReactiveXmlJdbcType.java @@ -48,7 +48,7 @@ protected X fromString(String string, JavaType javaType, WrapperOptions o if ( javaType.getJavaType() == SQLXML.class ) { throw LOG.unsupportedXmlType(); } - return options.getSessionFactory().getFastSessionServices().getXmlFormatMapper() + return options.getSessionFactory().getSessionFactoryOptions().getXmlFormatMapper() .fromString( string, javaType, options ); } diff --git a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/util/async/impl/AsyncCloseable.java b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/util/async/impl/AsyncCloseable.java index 806c38a96..d32b32146 100644 --- a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/util/async/impl/AsyncCloseable.java +++ b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/util/async/impl/AsyncCloseable.java @@ -17,7 +17,7 @@ *

* Examples of such resources are manually managed memory, open file handles, socket descriptors * etc. While similar to {@link AutoCloseable}, this interface should be used when the resource - * release operation may possibly be async. For example, if an object is thread-safe and has many + * release operation may be async. For example, if an object is thread-safe and has many * consumers, an implementation may require all current ongoing operations to complete before * resources are relinquished. * diff --git a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/util/async/impl/AsyncIterator.java b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/util/async/impl/AsyncIterator.java index 2680f56f8..0786e311e 100644 --- a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/util/async/impl/AsyncIterator.java +++ b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/util/async/impl/AsyncIterator.java @@ -51,7 +51,7 @@ * below. The difference is that the parallelization in that case is from producing values in * parallel, not consuming values in parallel. * - *

To implement an AsyncIterator you must only implement the {@link #nextStage()} method- + *

To implement an AsyncIterator you must only implement the {@link #nextStage()} method - * however, it is recommended that users avoid actually using nextStage to consume the results of * iteration. It is less expressive and it can also be error prone; it is easy to cause a stack * overflow by incorrectly recursing on calls to nextStage. You should prefer to use the other diff --git a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/util/async/impl/AsyncTrampoline.java b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/util/async/impl/AsyncTrampoline.java index cc2ef5702..b8feee8c6 100644 --- a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/util/async/impl/AsyncTrampoline.java +++ b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/util/async/impl/AsyncTrampoline.java @@ -174,7 +174,7 @@ T poll() { * *

* Effectively produces {@code fn(seed).thenCompose(fn).thenCompose(fn)... .thenCompose(fn)} until - * an value fails the predicate. Note that predicate will be applied on seed (like a while loop, + * a value fails the predicate. Note that predicate will be applied on seed (like a while loop, * the initial value is tested). If the predicate or fn throw an exception, * or the {@link CompletionStage} returned by fn completes exceptionally, iteration will stop and * an exceptional stage will be returned. diff --git a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/util/impl/CompletionStages.java b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/util/impl/CompletionStages.java index bb168d8f7..eb311aba6 100644 --- a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/util/impl/CompletionStages.java +++ b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/util/impl/CompletionStages.java @@ -301,7 +301,7 @@ public R getResult() throws T { if ( throwable == null ) { return result; } - throw (T) throwable; + throw throwable; } public CompletionStage getResultAsCompletionStage() { @@ -467,7 +467,7 @@ public static CompletionStage loop(int start, int end, IntPredicate filter } public static CompletionStage whileLoop(Supplier> loopSupplier) { - return asyncWhile( loopSupplier::get ); + return asyncWhile( loopSupplier ); } public static CompletionStage whileLoop(Supplier whileCondition, Supplier> loopSupplier) { diff --git a/hibernate-reactive-core/src/test/java/org/hibernate/reactive/BatchingConnectionTest.java b/hibernate-reactive-core/src/test/java/org/hibernate/reactive/BatchingConnectionTest.java index 1cdc423f0..0ce3d2e9d 100644 --- a/hibernate-reactive-core/src/test/java/org/hibernate/reactive/BatchingConnectionTest.java +++ b/hibernate-reactive-core/src/test/java/org/hibernate/reactive/BatchingConnectionTest.java @@ -41,7 +41,7 @@ protected Configuration constructConfiguration() { configuration.setProperty( AvailableSettings.STATEMENT_BATCH_SIZE, "5"); // Construct a tracker that collects query statements via the SqlStatementLogger framework. - // Pass in configuration properties to hand-off any actual logging properties + // Pass in configuration properties to hand off any actual logging properties sqlTracker = new SqlStatementTracker( BatchingConnectionTest::filter, configuration.getProperties() ); return configuration; } diff --git a/hibernate-reactive-core/src/test/java/org/hibernate/reactive/EagerElementCollectionForBasicTypeSetTest.java b/hibernate-reactive-core/src/test/java/org/hibernate/reactive/EagerElementCollectionForBasicTypeSetTest.java index ba183b406..176e30c37 100644 --- a/hibernate-reactive-core/src/test/java/org/hibernate/reactive/EagerElementCollectionForBasicTypeSetTest.java +++ b/hibernate-reactive-core/src/test/java/org/hibernate/reactive/EagerElementCollectionForBasicTypeSetTest.java @@ -442,7 +442,7 @@ private static void assertPhones(VertxTestContext context, Person person, String assertNotNull( person ); String[] sortedExpected = Arrays.stream( expectedPhones ).sorted() .sorted( String.CASE_INSENSITIVE_ORDER ) - .collect( Collectors.toList() ) + .toList() .toArray( new String[expectedPhones.length] ); List sortedActual = person.getPhones().stream() .sorted( String.CASE_INSENSITIVE_ORDER ) diff --git a/hibernate-reactive-core/src/test/java/org/hibernate/reactive/FindByIdWithLockTest.java b/hibernate-reactive-core/src/test/java/org/hibernate/reactive/FindByIdWithLockTest.java new file mode 100644 index 000000000..e78c549ca --- /dev/null +++ b/hibernate-reactive-core/src/test/java/org/hibernate/reactive/FindByIdWithLockTest.java @@ -0,0 +1,133 @@ +/* Hibernate, Relational Persistence for Idiomatic Java + * + * SPDX-License-Identifier: Apache-2.0 + * Copyright: Red Hat Inc. and Hibernate Authors + */ +package org.hibernate.reactive; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.concurrent.TimeUnit; + +import org.junit.jupiter.api.Test; + +import io.vertx.junit5.Timeout; +import io.vertx.junit5.VertxTestContext; +import jakarta.persistence.Entity; +import jakarta.persistence.FetchType; +import jakarta.persistence.Id; +import jakarta.persistence.LockModeType; +import jakarta.persistence.ManyToOne; +import jakarta.persistence.OneToMany; + +import static org.assertj.core.api.Assertions.assertThat; + +@Timeout(value = 10, timeUnit = TimeUnit.MINUTES) +public class FindByIdWithLockTest extends BaseReactiveTest { + private static final Long CHILD_ID = 1L; + + @Override + protected Collection> annotatedEntities() { + return List.of( Parent.class, Child.class ); + } + + @Test + public void testFindChild(VertxTestContext context) { + Parent parent = new Parent( 1L, "Lio" ); + Child child = new Child( CHILD_ID, "And" ); + test( + context, getMutinySessionFactory() + .withTransaction( session -> session.persistAll( parent, child ) ) + .chain( () -> getMutinySessionFactory() + .withTransaction( session -> session + .find( Child.class, CHILD_ID, LockModeType.PESSIMISTIC_WRITE ) + .invoke( c -> { + assertThat( c ).isNotNull(); + assertThat( c.getId() ).isEqualTo( CHILD_ID ); + } + ) ) ) + ); + } + + @Entity(name = "Parent") + public static class Parent { + + @Id + private Long id; + + private String name; + + @OneToMany(fetch = FetchType.EAGER) + public List children; + + public Parent() { + } + + public Parent(Long id, String name) { + this.id = id; + this.name = name; + } + + public void add(Child child) { + if ( children == null ) { + children = new ArrayList<>(); + } + children.add( child ); + } + + public Long getId() { + return id; + } + + public String getName() { + return name; + } + + public List getChildren() { + return children; + } + } + + + @Entity(name = "Child") + public static class Child { + + @Id + private Long id; + + public String name; + + @ManyToOne + public Parent parent; + + public Child() { + } + + public Child(Long id, String name) { + this.id = id; + this.name = name; + } + + public Child(Long id, String name, Parent parent) { + this.id = id; + this.name = name; + this.parent = parent; + parent.add( this ); + } + + public Long getId() { + return id; + } + + public String getName() { + return name; + } + + public Parent getParent() { + return parent; + } + } + + +} diff --git a/hibernate-reactive-core/src/test/java/org/hibernate/reactive/IdentityGenerationWithBatchingTest.java b/hibernate-reactive-core/src/test/java/org/hibernate/reactive/IdentityGenerationWithBatchingTest.java index acad8feba..3492532c1 100644 --- a/hibernate-reactive-core/src/test/java/org/hibernate/reactive/IdentityGenerationWithBatchingTest.java +++ b/hibernate-reactive-core/src/test/java/org/hibernate/reactive/IdentityGenerationWithBatchingTest.java @@ -63,7 +63,7 @@ public void test(VertxTestContext context) { } private Book[] asBooks(String[] titles) { - return Arrays.asList( titles ).stream().map( Book::new ).toArray( Book[]::new ); + return Arrays.stream( titles ).map( Book::new ).toArray( Book[]::new ); } @Entity(name = "Book") diff --git a/hibernate-reactive-core/src/test/java/org/hibernate/reactive/IdentityGeneratorDynamicInsertTest.java b/hibernate-reactive-core/src/test/java/org/hibernate/reactive/IdentityGeneratorDynamicInsertTest.java index 2454de0d3..9be6f748a 100644 --- a/hibernate-reactive-core/src/test/java/org/hibernate/reactive/IdentityGeneratorDynamicInsertTest.java +++ b/hibernate-reactive-core/src/test/java/org/hibernate/reactive/IdentityGeneratorDynamicInsertTest.java @@ -70,7 +70,7 @@ private CompletionStage populateDb() { return getSessionFactory() .withTransaction( (session, tx) -> session.persist( identities.toArray() ) ) .thenAccept( ignore -> { - Long assignedId = 0L; + long assignedId = 0L; for ( EntityWithIdentity identity : identities ) { assertNotNull( identity.id ); assertTrue( identity.id > assignedId ); diff --git a/hibernate-reactive-core/src/test/java/org/hibernate/reactive/IdentityGeneratorTest.java b/hibernate-reactive-core/src/test/java/org/hibernate/reactive/IdentityGeneratorTest.java index 61cc6c503..1d9a6c8b3 100644 --- a/hibernate-reactive-core/src/test/java/org/hibernate/reactive/IdentityGeneratorTest.java +++ b/hibernate-reactive-core/src/test/java/org/hibernate/reactive/IdentityGeneratorTest.java @@ -68,7 +68,7 @@ private CompletionStage populateDb() { return getSessionFactory() .withTransaction( (session, tx) -> session.persist( identities.toArray() ) ) .thenAccept( ignore -> { - Long assignedId = 0L; + long assignedId = 0L; for ( EntityWithIdentity identity : identities ) { assertNotNull( identity.id ); assertTrue( identity.id > assignedId ); diff --git a/hibernate-reactive-core/src/test/java/org/hibernate/reactive/IdentityGeneratorWithColumnTransformerTest.java b/hibernate-reactive-core/src/test/java/org/hibernate/reactive/IdentityGeneratorWithColumnTransformerTest.java index 3982e0c6b..a4d584719 100644 --- a/hibernate-reactive-core/src/test/java/org/hibernate/reactive/IdentityGeneratorWithColumnTransformerTest.java +++ b/hibernate-reactive-core/src/test/java/org/hibernate/reactive/IdentityGeneratorWithColumnTransformerTest.java @@ -72,7 +72,7 @@ private CompletionStage populateDb() { return getSessionFactory() .withTransaction( (session, tx) -> session.persist( identities.toArray() ) ) .thenAccept( ignore -> { - Long assignedId = 0L; + long assignedId = 0L; for ( EntityWithIdentity identity : identities ) { assertNotNull( identity.id ); assertTrue( identity.id > assignedId ); diff --git a/hibernate-reactive-core/src/test/java/org/hibernate/reactive/LazyInitializationExceptionTest.java b/hibernate-reactive-core/src/test/java/org/hibernate/reactive/LazyInitializationExceptionTest.java index bb04c0fda..4fcc72200 100644 --- a/hibernate-reactive-core/src/test/java/org/hibernate/reactive/LazyInitializationExceptionTest.java +++ b/hibernate-reactive-core/src/test/java/org/hibernate/reactive/LazyInitializationExceptionTest.java @@ -72,10 +72,14 @@ public void testLazyInitializationExceptionWithMutiny(VertxTestContext context) @Test public void testLazyInitializationExceptionWithStage(VertxTestContext context) { - test( context, assertThrown( LazyInitializationException.class, openSession() - .thenCompose( ss -> ss.createSelectionQuery( "from Artist", Artist.class ).getSingleResult() ) - .thenAccept( artist -> artist.getPaintings().size() ) ) - .thenAccept( LazyInitializationExceptionTest::assertLazyInitialization ) + test( + context, assertThrown( + LazyInitializationException.class, openSession() + .thenCompose( ss -> ss + .createSelectionQuery( "from Artist", Artist.class ) + .getSingleResult() ) + .thenAccept( artist -> artist.getPaintings().size() ) + ).thenAccept( LazyInitializationExceptionTest::assertLazyInitialization ) ); } diff --git a/hibernate-reactive-core/src/test/java/org/hibernate/reactive/MultithreadedInsertionTest.java b/hibernate-reactive-core/src/test/java/org/hibernate/reactive/MultithreadedInsertionTest.java index 9e31c20be..bd2a36d1e 100644 --- a/hibernate-reactive-core/src/test/java/org/hibernate/reactive/MultithreadedInsertionTest.java +++ b/hibernate-reactive-core/src/test/java/org/hibernate/reactive/MultithreadedInsertionTest.java @@ -37,6 +37,7 @@ import jakarta.persistence.Table; import static java.util.concurrent.TimeUnit.MINUTES; +import static org.assertj.core.api.Assertions.fail; import static org.hibernate.cfg.AvailableSettings.SHOW_SQL; import static org.hibernate.reactive.BaseReactiveTest.setDefaultProperties; import static org.hibernate.reactive.provider.Settings.POOL_CONNECT_TIMEOUT; @@ -233,11 +234,16 @@ public void reached() { public void waitForEveryone() { try { - countDownLatch.await( TIMEOUT_MINUTES, TimeUnit.MINUTES ); - prettyOut( "Everyone has now breached '" + label + "'" ); + boolean reachedZero = countDownLatch.await( TIMEOUT_MINUTES, MINUTES ); + if ( reachedZero ) { + prettyOut( "Everyone has now breached '" + label + "'" ); + } + else { + fail( "Time out reached" ); + } } catch ( InterruptedException e ) { - e.printStackTrace(); + fail( e ); } } } diff --git a/hibernate-reactive-core/src/test/java/org/hibernate/reactive/OneToManyArrayMergeTest.java b/hibernate-reactive-core/src/test/java/org/hibernate/reactive/OneToManyArrayMergeTest.java index e2eb826d9..8553f1624 100644 --- a/hibernate-reactive-core/src/test/java/org/hibernate/reactive/OneToManyArrayMergeTest.java +++ b/hibernate-reactive-core/src/test/java/org/hibernate/reactive/OneToManyArrayMergeTest.java @@ -111,9 +111,7 @@ public User(Long id, String firstname, String lastname, Role... roles) { this.firstname = firstname; this.lastname = lastname; this.roles = new Role[roles.length]; - for ( int i = 0; i < roles.length; i++ ) { - this.roles[i] = roles[i]; - } + System.arraycopy( roles, 0, this.roles, 0, roles.length ); } public Long getId() { diff --git a/hibernate-reactive-core/src/test/java/org/hibernate/reactive/OneToManyTest.java b/hibernate-reactive-core/src/test/java/org/hibernate/reactive/OneToManyTest.java index c3bec53b1..f0242ed71 100644 --- a/hibernate-reactive-core/src/test/java/org/hibernate/reactive/OneToManyTest.java +++ b/hibernate-reactive-core/src/test/java/org/hibernate/reactive/OneToManyTest.java @@ -45,9 +45,6 @@ public void testPersistAll(VertxTestContext context) { Author author = new Author( "Iain M Banks" ); author.books.add( book1 ); author.books.add( book2 ); - final Book[] bookArray = new Book[2]; - bookArray[0] = book1; - bookArray[1] = book2; test( context, getMutinySessionFactory() .withTransaction( session -> session.persistAll( book1, book2, author ) ) @@ -67,9 +64,6 @@ public void testFetchJoinQueryGetSingleResult(VertxTestContext context) { Author author = new Author( "Iain M Banks" ); author.books.add( book1 ); author.books.add( book2 ); - final Book[] bookArray = new Book[2]; - bookArray[0] = book1; - bookArray[1] = book2; test( context, getMutinySessionFactory() .withTransaction( session -> session.persistAll( book1, book2, author ) ) diff --git a/hibernate-reactive-core/src/test/java/org/hibernate/reactive/QueryTest.java b/hibernate-reactive-core/src/test/java/org/hibernate/reactive/QueryTest.java index d6146b2e5..c65c79ee4 100644 --- a/hibernate-reactive-core/src/test/java/org/hibernate/reactive/QueryTest.java +++ b/hibernate-reactive-core/src/test/java/org/hibernate/reactive/QueryTest.java @@ -138,7 +138,7 @@ public void testCriteriaEntityQuery(VertxTestContext context) { update.set( b.get( "title" ), "XXX" ); CriteriaDelete delete = builder.createCriteriaDelete( Book.class ); - b = delete.from( Book.class ); + delete.from( Book.class ); test( context, diff --git a/hibernate-reactive-core/src/test/java/org/hibernate/reactive/SoftDeleteTest.java b/hibernate-reactive-core/src/test/java/org/hibernate/reactive/SoftDeleteTest.java index 4ba2e844e..f77d86f61 100644 --- a/hibernate-reactive-core/src/test/java/org/hibernate/reactive/SoftDeleteTest.java +++ b/hibernate-reactive-core/src/test/java/org/hibernate/reactive/SoftDeleteTest.java @@ -172,7 +172,7 @@ private void testSoftDelete( } ) ) // Delete an entity - .call( deleteEntity::get ) + .call( deleteEntity ) // Test select all .call( () -> getMutinySessionFactory().withTransaction( s -> s .createSelectionQuery( "from " + entityClass.getSimpleName() + " order by id", Object.class ) diff --git a/hibernate-reactive-core/src/test/java/org/hibernate/reactive/containers/CockroachDBDatabase.java b/hibernate-reactive-core/src/test/java/org/hibernate/reactive/containers/CockroachDBDatabase.java index 103723127..ae4d34d39 100644 --- a/hibernate-reactive-core/src/test/java/org/hibernate/reactive/containers/CockroachDBDatabase.java +++ b/hibernate-reactive-core/src/test/java/org/hibernate/reactive/containers/CockroachDBDatabase.java @@ -63,7 +63,7 @@ private static String disableSslMode(String url) { } /** - * Temporary tables support is experimental but we need it when updating entities in a hierarchy + * We need temporary tables when updating entities in a hierarchy */ private static void enableTemporaryTables() { runSql( "SET CLUSTER SETTING sql.defaults.experimental_temporary_tables.enabled = 'true';" ); diff --git a/hibernate-reactive-core/src/test/java/org/hibernate/reactive/types/Json.java b/hibernate-reactive-core/src/test/java/org/hibernate/reactive/types/Json.java index 2df6f008a..9af3a2b76 100644 --- a/hibernate-reactive-core/src/test/java/org/hibernate/reactive/types/Json.java +++ b/hibernate-reactive-core/src/test/java/org/hibernate/reactive/types/Json.java @@ -61,7 +61,7 @@ public void nullSafeSet(PreparedStatement st, JsonObject value, int index, Share @Override public JsonObject deepCopy(JsonObject value) { - return value == null ? null : ( (JsonObject) value ).copy(); + return value == null ? null : value.copy(); } @Override