From 257ce5cbbe6727e1fbd20c9fb09ec61867527fd6 Mon Sep 17 00:00:00 2001
From: Gavin King
Date: Thu, 1 May 2025 08:08:06 +0200
Subject: [PATCH] fixes before release
1. fix some more incorrect casts to ReactiveSession or ReactiveSessionImpl
2. remove the SS.upsert() method taking an entity name (we don't need it)
3. some minor code cleanups in EntityTypes and CollectionTypes
---
.../ReactivePersistenceContextAdapter.java | 7 +-
.../reactive/engine/impl/CollectionTypes.java | 200 +++++++++---------
.../reactive/engine/impl/EntityTypes.java | 20 +-
...ctiveSharedSessionContractImplementor.java | 5 +
...tiveInitializeCollectionEventListener.java | 29 +--
.../org/hibernate/reactive/mutiny/Mutiny.java | 12 --
.../mutiny/impl/MutinySessionImpl.java | 38 ++--
.../impl/MutinyStatelessSessionImpl.java | 5 -
.../impl/ReactiveAbstractEntityPersister.java | 5 +-
.../reactive/session/ReactiveSession.java | 7 -
.../session/ReactiveStatelessSession.java | 6 -
.../session/impl/ReactiveSessionImpl.java | 15 +-
.../impl/ReactiveStatelessSessionImpl.java | 69 ++++--
.../org/hibernate/reactive/stage/Stage.java | 9 -
.../reactive/stage/impl/StageSessionImpl.java | 45 ++--
.../stage/impl/StageStatelessSessionImpl.java | 5 -
.../org/hibernate/reactive/UpsertTest.java | 56 -----
17 files changed, 206 insertions(+), 327 deletions(-)
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
index 3dfc8dcd0..6d87416b4 100644
--- 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
@@ -37,9 +37,9 @@
import org.hibernate.persister.collection.CollectionPersister;
import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.reactive.engine.impl.ReactiveCallbackImpl;
+import org.hibernate.reactive.engine.spi.ReactiveSharedSessionContractImplementor;
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;
@@ -79,8 +79,9 @@ private class NonLazyCollectionInitializer implements Consumer nonLazyCollection) {
if ( !nonLazyCollection.wasInitialized() ) {
- stage = stage.thenCompose( v -> ( (ReactiveSession) getSession() )
- .reactiveInitializeCollection( nonLazyCollection, false ) );
+ stage = stage.thenCompose( v ->
+ ( (ReactiveSharedSessionContractImplementor) getSession() )
+ .reactiveInitializeCollection( nonLazyCollection, false ) );
}
}
}
diff --git a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/engine/impl/CollectionTypes.java b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/engine/impl/CollectionTypes.java
index 4bc488bb6..bb72946ad 100644
--- a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/engine/impl/CollectionTypes.java
+++ b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/engine/impl/CollectionTypes.java
@@ -110,20 +110,18 @@ else if ( target instanceof Map, ?> map ) {
}
else {
final PersistenceContext persistenceContext = session.getPersistenceContext();
- final PersistentCollection> collectionHolder = persistenceContext.getCollectionHolder( target );
- if ( collectionHolder != null ) {
- if ( collectionHolder instanceof PersistentArrayHolder> arrayHolder ) {
- persistenceContext.removeCollectionHolder( target );
- arrayHolder.beginRead();
- final PluralAttributeMapping attributeMapping =
- persistenceContext.getCollectionEntry( collectionHolder )
- .getLoadedPersister().getAttributeMapping();
- arrayHolder.injectLoadedState( attributeMapping, null );
- arrayHolder.endRead();
- arrayHolder.dirty();
- persistenceContext.addCollectionHolder( collectionHolder );
- return arrayHolder.getArray();
- }
+ if ( persistenceContext.getCollectionHolder( target )
+ instanceof PersistentArrayHolder> arrayHolder ) {
+ persistenceContext.removeCollectionHolder( target );
+ arrayHolder.beginRead();
+ final PluralAttributeMapping attributeMapping =
+ persistenceContext.getCollectionEntry( arrayHolder )
+ .getLoadedPersister().getAttributeMapping();
+ arrayHolder.injectLoadedState( attributeMapping, null );
+ arrayHolder.endRead();
+ arrayHolder.dirty();
+ persistenceContext.addCollectionHolder( arrayHolder );
+ return arrayHolder.getArray();
}
}
return null;
@@ -142,8 +140,9 @@ private static Object replaceUninitializedOriginal(
// A managed entity with an uninitialized collection is being merged,
// We need to replace any detached entities in the queued operations
// with managed copies.
- final AbstractPersistentCollection> pc = (AbstractPersistentCollection>) original;
- pc.replaceQueuedOperationValues(
+ final AbstractPersistentCollection> collection =
+ (AbstractPersistentCollection>) original;
+ collection.replaceQueuedOperationValues(
session.getFactory()
.getMappingMetamodel()
.getCollectionDescriptor( type.getRole() ), copyCache
@@ -182,18 +181,20 @@ private static CompletionStage
- // One thing to be careful of here is a "bare" original collection
- // in which case we should never ever ever reset the dirty flag
- // on the target because we simply do not know...
- if ( original instanceof PersistentCollection> originalPersistentCollection
- && result instanceof PersistentCollection> resultPersistentCollection ) {
- return preserveSnapshot(
- originalPersistentCollection, resultPersistentCollection,
- elemType, owner, copyCache, session
- ).thenApply( v -> {
- if ( !originalPersistentCollection.isDirty() ) {
- resultPersistentCollection.clearDirty();
- }
- return result;
- } );
- }
- else {
- return completedFuture( result );
- }
- } );
+ return loop( (Collection>) original,
+ o -> getReplace( elemType, o, owner, session, copyCache )
+ .thenAccept( result::add ) )
+ .thenCompose( v -> preserveSnapshotIfNecessary( original, result, owner, copyCache, session, elemType ) );
+ }
+
+ private static CompletionStage preserveSnapshotIfNecessary(
+ Object original,
+ Collection result,
+ Object owner,
+ Map copyCache,
+ SessionImplementor session,
+ Type elemType) {
+ // if the original is a PersistentCollection, and that original
+ // was not flagged as dirty, then reset the target's dirty flag
+ // here after the copy operation.
+ //
+ // One thing to be careful of here is a "bare" original collection
+ // in which case we should never ever ever reset the dirty flag
+ // on the target because we simply do not know...
+ if ( original instanceof PersistentCollection> originalCollection
+ && result instanceof PersistentCollection> resultCollection ) {
+ return preserveSnapshot(
+ originalCollection, resultCollection,
+ elemType, owner, copyCache, session
+ ).thenApply( v -> {
+ if ( !originalCollection.isDirty() ) {
+ resultCollection.clearDirty();
+ }
+ return result;
+ } );
+ }
+ else {
+ return completedFuture( result );
+ }
}
private static CompletionStage replaceMapTypeElements(
CollectionType type,
- Map original,
+ Map, ?> original,
Map target,
Object owner,
Map copyCache,
SessionImplementor session) {
- final CollectionPersister persister = session.getFactory().getRuntimeMetamodels()
- .getMappingMetamodel().getCollectionDescriptor( type.getRole() );
- final Map result = target;
- result.clear();
-
+ final CollectionPersister persister =
+ session.getFactory().getRuntimeMetamodels().getMappingMetamodel()
+ .getCollectionDescriptor( type.getRole() );
+ target.clear();
return loop(
original.entrySet(), entry -> {
- final Map.Entry me = entry;
+ final Map.Entry, ?> me = entry;
return getReplace( persister.getIndexType(), me.getKey(), owner, session, copyCache )
.thenCompose( key -> getReplace(
persister.getElementType(),
@@ -301,10 +308,10 @@ private static CompletionStage replaceMapTypeElements(
owner,
session,
copyCache
- ).thenAccept( value -> result.put( key, value ) )
+ ).thenAccept( value -> target.put( key, value ) )
);
}
- ).thenApply( unused -> result );
+ ).thenApply( unused -> target);
}
private static CompletionStage replaceArrayTypeElements(
@@ -325,8 +332,8 @@ private static CompletionStage replaceArrayTypeElements(
}
final Type elemType = type.getElementType( session.getFactory() );
- return loop(
- 0, length, i -> getReplace( elemType, Array.get( original, i ), owner, session, copyCache )
+ return loop( 0, length,
+ i -> getReplace( elemType, Array.get( original, i ), owner, session, copyCache )
.thenApply( o -> {
Array.set( result, i, o );
return result;
@@ -345,18 +352,14 @@ private static CompletionStage getReplace(
private static CompletionStage getReplace(
Type elemType,
- Object o,
+ Object object,
Object target,
Object owner,
SessionImplementor session,
Map copyCache) {
- if ( elemType instanceof EntityType ) {
- return EntityTypes.replace( (EntityType) elemType, o, target, session, owner, copyCache );
- }
- else {
- final Object replace = elemType.replace( o, target, session, owner, copyCache );
- return completedFuture( replace );
- }
+ return elemType instanceof EntityType entityType
+ ? EntityTypes.replace( entityType, object, target, session, owner, copyCache )
+ : completedFuture( elemType.replace( object, target, session, owner, copyCache) );
}
/**
@@ -374,7 +377,9 @@ private static CompletionStage preserveSnapshot(
return createSnapshot( original, result, elemType, owner, copyCache, session )
.thenAccept( serializable -> ce.resetStoredSnapshot( result, serializable ) );
}
- return voidFuture();
+ else {
+ return voidFuture();
+ }
}
/**
@@ -412,8 +417,8 @@ private static CompletionStage createArraySnapshot(
Object owner,
Map copyCache,
SessionImplementor session) {
- return loop(
- 0, array.length, i -> getReplace( elemType, array[i], owner, session, copyCache )
+ return loop( 0, array.length,
+ i -> getReplace( elemType, array[i], owner, session, copyCache )
.thenAccept( o -> array[i] = o )
).thenApply( unused -> array );
}
@@ -421,29 +426,26 @@ private static CompletionStage createArraySnapshot(
/**
* @see CollectionType#createMapSnapshot(Map, PersistentCollection, Type, Object, Map, SharedSessionContractImplementor)
*/
- private static CompletionStage createMapSnapshot(
- Map, ?> map,
+ private static CompletionStage createMapSnapshot(
+ Map map,
PersistentCollection> result,
Type elemType,
Object owner,
Map copyCache,
SessionImplementor session) {
final Map, ?> resultSnapshot = (Map, ?>) result.getStoredSnapshot();
- final Map targetMap;
- if ( map instanceof SortedMap, ?> sortedMap ) {
- //noinspection unchecked, rawtypes
- targetMap = new TreeMap( sortedMap.comparator() );
- }
- else {
- targetMap = mapOfSize( map.size() );
- }
- return loop(
- map.entrySet(), entry ->
- getReplace( elemType, entry.getValue(), resultSnapshot, owner, session, copyCache )
- .thenAccept( newValue -> {
- final Object key = entry.getKey();
- targetMap.put( key == entry.getValue() ? newValue : key, newValue );
- } )
+ final Map targetMap =
+ map instanceof SortedMap sortedMap
+ ? new TreeMap<>( sortedMap.comparator() )
+ : mapOfSize(map.size());
+ return loop( map.entrySet(),
+ entry -> getReplace( elemType, entry.getValue(), resultSnapshot, owner, session, copyCache )
+ .thenAccept( newValue -> {
+ final K key = entry.getKey();
+ final V value = entry.getValue();
+ //noinspection unchecked
+ targetMap.put( key == value ? (K) newValue : key, (V) newValue );
+ } )
).thenApply( v -> (Serializable) targetMap );
}
@@ -457,8 +459,8 @@ private static CompletionStage createListSnapshot(
Map copyCache,
SessionImplementor session) {
final ArrayList targetList = new ArrayList<>( list.size() );
- return loop(
- list, obj -> getReplace( elemType, obj, owner, session, copyCache )
+ return loop( list,
+ obj -> getReplace( elemType, obj, owner, session, copyCache )
.thenAccept( targetList::add )
).thenApply( unused -> targetList );
}
@@ -472,9 +474,9 @@ private static Object instantiateResultIfNecessary(CollectionType type, Object o
// by default just use an unanticipated capacity since we don't
// know how to extract the capacity to use from original here...
return target == null
- || target == original
- || target == UNFETCHED_PROPERTY
- || target instanceof PersistentCollection> collection && collection.isWrapper( original )
+ || target == original
+ || target == UNFETCHED_PROPERTY
+ || target instanceof PersistentCollection> collection && collection.isWrapper( original )
? type.instantiate( -1 )
: target;
}
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 0bb0c75ae..9176e853c 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
@@ -22,9 +22,10 @@
import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.proxy.HibernateProxy;
import org.hibernate.proxy.LazyInitializer;
+import org.hibernate.reactive.engine.spi.ReactiveSharedSessionContractImplementor;
import org.hibernate.reactive.persister.entity.impl.ReactiveEntityPersister;
+import org.hibernate.reactive.session.ReactiveQueryProducer;
import org.hibernate.reactive.session.impl.ReactiveQueryExecutorLookup;
-import org.hibernate.reactive.session.impl.ReactiveSessionImpl;
import org.hibernate.type.CollectionType;
import org.hibernate.type.EntityType;
import org.hibernate.type.ForeignKeyDirection;
@@ -158,8 +159,8 @@ public static CompletionStage replace(
final Object owner,
final Map copyCache) {
Object[] copied = new Object[original.length];
- return loop(
- 0, types.length, i -> replace( original, target, types, session, owner, copyCache, i, copied )
+ return loop( 0, types.length,
+ i -> replace( original, target, types, session, owner, copyCache, i, copied )
).thenApply( v -> copied );
}
@@ -175,8 +176,7 @@ public static CompletionStage replace(
final Map copyCache,
final ForeignKeyDirection foreignKeyDirection) {
Object[] copied = new Object[original.length];
- return loop(
- 0, types.length,
+ return loop( 0, types.length,
i -> replace( original, target, types, session, owner, copyCache, foreignKeyDirection, i, copied )
).thenApply( v -> copied );
}
@@ -268,7 +268,7 @@ private static CompletionStage resolveIdOrUniqueKey(
// as a ComponentType. In the case that the entity is unfetched, we need to
// explicitly fetch it here before calling replace(). (Note that in Hibernate
// ORM this is unnecessary due to transparent lazy fetching.)
- return ( (ReactiveSessionImpl) session )
+ return ( (ReactiveQueryProducer) session )
.reactiveFetch( id, true )
.thenCompose( fetched -> {
Object idOrUniqueKey = entityType
@@ -340,10 +340,11 @@ private static CompletionStage getIdentifierFromHibernateProxy(
EntityType entityType,
HibernateProxy proxy,
SharedSessionContractImplementor session) {
- LazyInitializer initializer = proxy.getHibernateLazyInitializer();
+ final LazyInitializer initializer = proxy.getHibernateLazyInitializer();
final String entityName = initializer.getEntityName();
final Object identifier = initializer.getIdentifier();
- return ( (ReactiveSessionImpl) session ).reactiveImmediateLoad( entityName, identifier )
+ return ( (ReactiveSharedSessionContractImplementor) session )
+ .reactiveImmediateLoad( entityName, identifier )
.thenApply( entity -> {
checkEntityFound( session, entityName, identifier, entity );
initializer.setSession( session );
@@ -372,7 +373,8 @@ private static CompletionStage loadHibernateProxyEntity(
LazyInitializer initializer = ( (HibernateProxy) entity ).getHibernateLazyInitializer();
final String entityName = initializer.getEntityName();
final Object identifier = initializer.getIdentifier();
- return ( (ReactiveSessionImpl) session ).reactiveImmediateLoad( entityName, identifier )
+ return ( (ReactiveSharedSessionContractImplementor) session )
+ .reactiveImmediateLoad( entityName, identifier )
.thenApply( result -> {
checkEntityFound( session, entityName, identifier, result );
return result;
diff --git a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/engine/spi/ReactiveSharedSessionContractImplementor.java b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/engine/spi/ReactiveSharedSessionContractImplementor.java
index 1ab340380..9bdc5742a 100644
--- a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/engine/spi/ReactiveSharedSessionContractImplementor.java
+++ b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/engine/spi/ReactiveSharedSessionContractImplementor.java
@@ -9,6 +9,7 @@
import java.util.concurrent.CompletionStage;
+import org.hibernate.collection.spi.PersistentCollection;
import org.hibernate.engine.spi.PersistenceContext;
import static org.hibernate.reactive.util.impl.CompletionStages.falseFuture;
@@ -22,5 +23,9 @@ default CompletionStage reactiveAutoFlushIfRequired(Set querySp
return falseFuture();
}
+ CompletionStage reactiveImmediateLoad(String entityName, Object id);
+
+ CompletionStage reactiveInitializeCollection(PersistentCollection> collection, boolean writing);
+
PersistenceContext getPersistenceContext();
}
diff --git a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/event/impl/DefaultReactiveInitializeCollectionEventListener.java b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/event/impl/DefaultReactiveInitializeCollectionEventListener.java
index 20466abd2..5547fcc74 100644
--- a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/event/impl/DefaultReactiveInitializeCollectionEventListener.java
+++ b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/event/impl/DefaultReactiveInitializeCollectionEventListener.java
@@ -23,9 +23,9 @@
import org.hibernate.reactive.logging.impl.Log;
import org.hibernate.reactive.logging.impl.LoggerFactory;
import org.hibernate.reactive.persister.collection.impl.ReactiveCollectionPersister;
-import org.hibernate.sql.results.internal.ResultsHelper;
import org.hibernate.stat.spi.StatisticsImplementor;
+import static org.hibernate.event.internal.DefaultInitializeCollectionEventListener.handlePotentiallyEmptyCollection;
import static org.hibernate.pretty.MessageHelper.collectionInfoString;
import static org.hibernate.reactive.util.impl.CompletionStages.failedFuture;
import static org.hibernate.reactive.util.impl.CompletionStages.voidFuture;
@@ -59,7 +59,8 @@ public CompletionStage onReactiveInitializeCollection(InitializeCollection
final CollectionPersister loadedPersister = ce.getLoadedPersister();
final Object loadedKey = ce.getLoadedKey();
if ( LOG.isTraceEnabled() ) {
- LOG.tracev( "Initializing collection {0}", collectionInfoString( loadedPersister, collection, loadedKey, source ) );
+ LOG.tracev( "Initializing collection {0}",
+ collectionInfoString( loadedPersister, collection, loadedKey, source ) );
LOG.trace( "Checking second-level cache" );
}
@@ -76,11 +77,8 @@ public CompletionStage onReactiveInitializeCollection(InitializeCollection
}
return ( (ReactiveCollectionPersister) loadedPersister )
.reactiveInitialize( loadedKey, source )
- .thenApply( list -> {
- handlePotentiallyEmptyCollection( collection, source, ce, loadedPersister );
- return list;
- } )
- .thenAccept( list -> {
+ .thenAccept( v -> {
+ handlePotentiallyEmptyCollection( collection, source.getPersistenceContext(), ce, loadedPersister );
if ( LOG.isTraceEnabled() ) {
LOG.trace( "Collection initialized" );
}
@@ -93,23 +91,6 @@ public CompletionStage onReactiveInitializeCollection(InitializeCollection
}
}
- private void handlePotentiallyEmptyCollection(
- PersistentCollection> collection,
- SessionImplementor source,
- CollectionEntry ce,
- CollectionPersister loadedPersister) {
- if ( !collection.wasInitialized() ) {
- collection.initializeEmptyCollection( loadedPersister );
- ResultsHelper.finalizeCollectionLoading(
- source.getPersistenceContext(),
- loadedPersister,
- collection,
- ce.getLoadedKey(),
- true
- );
- }
- }
-
/**
* Try to initialize a collection from the cache
*
diff --git a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/mutiny/Mutiny.java b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/mutiny/Mutiny.java
index c3608061b..aab884e76 100644
--- a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/mutiny/Mutiny.java
+++ b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/mutiny/Mutiny.java
@@ -1745,18 +1745,6 @@ default Uni get(Class entityClass, Object id, LockModeType lockModeTyp
@Incubating
Uni upsert(Object entity);
- /**
- * Use a SQL {@code merge into} statement to perform an upsert.
- *
- * @param entityName The entityName for the entity to be merged
- * @param entity a detached entity instance
- * @throws org.hibernate.TransientObjectException is the entity is transient
- *
- * @see org.hibernate.StatelessSession#upsert(String, Object)
- */
- @Incubating
- Uni upsert(String entityName, Object entity);
-
/**
* Use a SQL {@code merge into} statement to perform
* an upsert on multiple rows using the size of the given array
diff --git a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/mutiny/impl/MutinySessionImpl.java b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/mutiny/impl/MutinySessionImpl.java
index 8a4149104..c80be96ed 100644
--- a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/mutiny/impl/MutinySessionImpl.java
+++ b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/mutiny/impl/MutinySessionImpl.java
@@ -332,36 +332,22 @@ public Uni lock(Object entity, LockOptions lockOptions) {
@Override
public FlushMode getFlushMode() {
- switch ( delegate.getHibernateFlushMode() ) {
- case MANUAL:
- return FlushMode.MANUAL;
- case COMMIT:
- return FlushMode.COMMIT;
- case AUTO:
- return FlushMode.AUTO;
- case ALWAYS:
- return FlushMode.ALWAYS;
- default:
- throw LOG.impossibleFlushModeIllegalState();
- }
+ return switch (delegate.getHibernateFlushMode()) {
+ case MANUAL -> FlushMode.MANUAL;
+ case COMMIT -> FlushMode.COMMIT;
+ case AUTO -> FlushMode.AUTO;
+ case ALWAYS -> FlushMode.ALWAYS;
+ };
}
@Override
public Mutiny.Session setFlushMode(FlushMode flushMode) {
- switch ( flushMode ) {
- case COMMIT:
- delegate.setHibernateFlushMode( FlushMode.COMMIT );
- break;
- case AUTO:
- delegate.setHibernateFlushMode( FlushMode.AUTO );
- break;
- case MANUAL:
- delegate.setHibernateFlushMode( FlushMode.MANUAL );
- break;
- case ALWAYS:
- delegate.setHibernateFlushMode( FlushMode.ALWAYS );
- break;
- }
+ delegate.setHibernateFlushMode( switch ( flushMode ) {
+ case COMMIT -> org.hibernate.FlushMode.COMMIT;
+ case AUTO -> org.hibernate.FlushMode.AUTO;
+ case MANUAL -> org.hibernate.FlushMode.MANUAL;
+ case ALWAYS -> org.hibernate.FlushMode.ALWAYS;
+ } );
return this;
}
diff --git a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/mutiny/impl/MutinyStatelessSessionImpl.java b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/mutiny/impl/MutinyStatelessSessionImpl.java
index f5a6352c1..21602c48f 100644
--- a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/mutiny/impl/MutinyStatelessSessionImpl.java
+++ b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/mutiny/impl/MutinyStatelessSessionImpl.java
@@ -240,11 +240,6 @@ public Uni upsert(Object entity) {
return uni( () -> delegate.reactiveUpsert( entity ) );
}
- @Override
- public Uni upsert(String entityName, Object entity) {
- return uni( () -> delegate.reactiveUpsert( entityName, entity ) );
- }
-
@Override
public Uni upsertAll(Object... entities) {
return uni( () -> delegate.reactiveUpsertAll( entities.length, entities ) );
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 c1015939c..0ebebe603 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
@@ -55,6 +55,7 @@
import org.hibernate.metamodel.mapping.internal.MappingModelCreationProcess;
import org.hibernate.persister.entity.AbstractEntityPersister;
import org.hibernate.reactive.adaptor.impl.PreparedStatementAdaptor;
+import org.hibernate.reactive.engine.spi.ReactiveSharedSessionContractImplementor;
import org.hibernate.reactive.generator.values.internal.ReactiveGeneratedValuesHelper;
import org.hibernate.reactive.loader.ast.internal.ReactiveSingleIdArrayLoadPlan;
import org.hibernate.reactive.loader.ast.spi.ReactiveSingleIdEntityLoader;
@@ -62,7 +63,6 @@
import org.hibernate.reactive.metamodel.mapping.internal.ReactiveCompoundNaturalIdMapping;
import org.hibernate.reactive.metamodel.mapping.internal.ReactiveSimpleNaturalIdMapping;
import org.hibernate.reactive.pool.ReactiveConnection;
-import org.hibernate.reactive.session.ReactiveSession;
import org.hibernate.reactive.session.impl.ReactiveQueryExecutorLookup;
import org.hibernate.sql.SimpleSelect;
import org.hibernate.sql.Update;
@@ -359,7 +359,8 @@ else if ( result instanceof PersistentCollection ) {
final PersistentCollection> collection = (PersistentCollection>) result;
return collection.wasInitialized()
? completedFuture( (T) collection )
- : ( (ReactiveSession) session ).reactiveInitializeCollection( collection, false )
+ : ( (ReactiveSharedSessionContractImplementor) session )
+ .reactiveInitializeCollection( collection, false )
.thenApply( v -> (T) result );
}
else {
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 88cfe3ec6..dbb7a818f 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
@@ -16,7 +16,6 @@
import org.hibernate.LockMode;
import org.hibernate.LockOptions;
import org.hibernate.UnknownProfileException;
-import org.hibernate.collection.spi.PersistentCollection;
import org.hibernate.engine.spi.EntityEntry;
import org.hibernate.engine.spi.SessionImplementor;
import org.hibernate.event.spi.DeleteContext;
@@ -59,8 +58,6 @@ public interface ReactiveSession extends ReactiveQueryProducer, ReactiveSharedSe
CompletionStage reactiveRemove(Object entity);
- CompletionStage reactiveRemove(String entityName, boolean isCascadeDeleteEnabled, DeleteContext transientObjects);
-
CompletionStage reactiveRemove(String entityName, Object child, boolean isCascadeDeleteEnabled, DeleteContext transientEntities);
CompletionStage reactiveMerge(T object);
@@ -91,10 +88,6 @@ public interface ReactiveSession extends ReactiveQueryProducer, ReactiveSharedSe
CompletionStage reactiveFind(Class entityClass, Map naturalIds);
- CompletionStage reactiveImmediateLoad(String entityName, Object id);
-
- CompletionStage reactiveInitializeCollection(PersistentCollection> collection, boolean writing);
-
CompletionStage reactiveRemoveOrphanBeforeUpdates(String entityName, Object child);
void setHibernateFlushMode(FlushMode flushMode);
diff --git a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/session/ReactiveStatelessSession.java b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/session/ReactiveStatelessSession.java
index e6d2aa1ee..006fbb63f 100644
--- a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/session/ReactiveStatelessSession.java
+++ b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/session/ReactiveStatelessSession.java
@@ -46,18 +46,12 @@ public interface ReactiveStatelessSession extends ReactiveQueryProducer, Reactiv
CompletionStage reactiveUpsert(Object entity);
- CompletionStage reactiveUpsert(String entityName, Object entity);
-
CompletionStage reactiveUpsertAll(int batchSize, Object... entities);
CompletionStage reactiveRefresh(Object entity);
- CompletionStage reactiveRefresh(String entityName, Object entity);
-
CompletionStage reactiveRefresh(Object entity, LockMode lockMode);
- CompletionStage reactiveRefresh(String entityName, Object entity, LockMode lockMode);
-
CompletionStage reactiveInsertAll(Object... entities);
CompletionStage reactiveInsertAll(int batchSize, Object... entities);
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 02b392a27..d86ffd7d1 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
@@ -30,14 +30,12 @@
import org.hibernate.engine.spi.PersistentAttributeInterceptor;
import org.hibernate.engine.spi.SessionImplementor;
import org.hibernate.engine.spi.Status;
-import org.hibernate.event.service.spi.EventListenerGroup;
import org.hibernate.event.spi.AutoFlushEvent;
import org.hibernate.event.spi.DeleteContext;
import org.hibernate.event.spi.DeleteEvent;
import org.hibernate.event.spi.EventSource;
import org.hibernate.event.spi.FlushEvent;
import org.hibernate.event.spi.InitializeCollectionEvent;
-import org.hibernate.event.spi.InitializeCollectionEventListener;
import org.hibernate.event.spi.LoadEvent;
import org.hibernate.event.spi.LoadEventListener;
import org.hibernate.event.spi.LockEvent;
@@ -826,8 +824,7 @@ public CompletionStage reactiveInitializeCollection(PersistentCollection
pulseTransactionCoordinator();
InitializeCollectionEvent event = new InitializeCollectionEvent( collection, this );
- EventListenerGroup eventListenerGroupInitCollection = getFactory().getEventListenerGroups().eventListenerGroup_INIT_COLLECTION;
- return eventListenerGroupInitCollection
+ return getFactory().getEventListenerGroups().eventListenerGroup_INIT_COLLECTION
.fireEventOnEachListener(
event,
(DefaultReactiveInitializeCollectionEventListener l) -> l::onReactiveInitializeCollection
@@ -920,16 +917,6 @@ public CompletionStage reactiveRemove(Object entity) {
return fireRemove( new DeleteEvent( entity, this ) );
}
- @Override
- public CompletionStage reactiveRemove(
- String entityName,
- boolean isCascadeDeleteEnabled,
- DeleteContext transientEntities)
- throws HibernateException {
- // I'm not quite sure if we need this method
- return reactiveRemove( entityName, null, isCascadeDeleteEnabled, transientEntities );
- }
-
@Override
public CompletionStage reactiveRemove(
String entityName,
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 84483afb3..be9dc87b0 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
@@ -7,6 +7,7 @@
import org.hibernate.HibernateException;
import org.hibernate.LockMode;
+import org.hibernate.SessionException;
import org.hibernate.UnknownEntityTypeException;
import org.hibernate.UnresolvableObjectException;
import org.hibernate.bytecode.enhance.spi.interceptor.EnhancementAsProxyLazinessInterceptor;
@@ -14,6 +15,7 @@
import org.hibernate.collection.spi.PersistentCollection;
import org.hibernate.dialect.Dialect;
import org.hibernate.engine.internal.ReactivePersistenceContextAdapter;
+import org.hibernate.engine.spi.CollectionEntry;
import org.hibernate.engine.spi.LoadQueryInfluencers;
import org.hibernate.engine.spi.PersistenceContext;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
@@ -101,6 +103,7 @@
import static org.hibernate.internal.util.StringHelper.isNotEmpty;
import static org.hibernate.loader.ast.spi.CascadingFetchProfile.REFRESH;
import static org.hibernate.loader.internal.CacheLoadHelper.initializeCollectionFromCache;
+import static org.hibernate.pretty.MessageHelper.collectionInfoString;
import static org.hibernate.pretty.MessageHelper.infoString;
import static org.hibernate.proxy.HibernateProxy.extractLazyInitializer;
import static org.hibernate.reactive.id.impl.IdentifierGeneration.castToIdentifierType;
@@ -590,18 +593,12 @@ public CompletionStage reactiveRefresh(Object entity) {
return reactiveRefresh( bestGuessEntityName( entity ), entity, LockMode.NONE );
}
- @Override
- public CompletionStage reactiveRefresh(String entityName, Object entity) {
- return reactiveRefresh( entityName, entity, LockMode.NONE );
- }
-
@Override
public CompletionStage reactiveRefresh(Object entity, LockMode lockMode) {
return reactiveRefresh( bestGuessEntityName( entity ), entity, lockMode );
}
- @Override
- public CompletionStage reactiveRefresh(String entityName, Object entity, LockMode lockMode) {
+ private CompletionStage reactiveRefresh(String entityName, Object entity, LockMode lockMode) {
checkOpen();
final ReactiveEntityPersister persister = getEntityPersister( entityName, entity );
final Object id = persister.getIdentifier( entity, this );
@@ -642,16 +639,7 @@ private CompletionStage> fromInternalFetchProfile(CascadingFetchProfile cascad
@Override
public CompletionStage reactiveUpsert(Object entity) {
checkOpen();
- return reactiveUpsert( null, entity );
- }
-
- /**
- * @see StatelessSessionImpl#upsert(String, Object)
- */
- @Override
- public CompletionStage reactiveUpsert(String entityName, Object entity) {
- checkOpen();
- final ReactiveEntityPersister persister = getEntityPersister( entityName, entity );
+ final ReactiveEntityPersister persister = getEntityPersister( null, entity );
final Object id = idToUpsert( entity, persister );
final Object[] state = persister.getValues( entity );
if ( firePreUpsert( entity, id, state, persister ) ) {
@@ -764,6 +752,15 @@ public CompletionStage reactiveInternalLoad(String entityName, Object id
: completedFuture( object );
}
+ @Override
+ public CompletionStage reactiveImmediateLoad(String entityName, Object id) {
+ if ( persistenceContext.isLoadFinished() ) {
+ throw new SessionException( "proxies cannot be fetched by a stateless session" );
+ }
+ // unless we are still in the process of handling a top-level load
+ return reactiveGet( entityName, id );
+ }
+
@Override
protected Object internalLoadGet(String entityName, Object id, PersistenceContext persistenceContext) {
// otherwise immediately materialize it
@@ -775,6 +772,44 @@ protected Object internalLoadGet(String entityName, Object id, PersistenceContex
.whenComplete( (r, e) -> persistenceContext.afterLoad() );
}
+ @Override
+ public CompletionStage reactiveInitializeCollection(PersistentCollection> collection, boolean writing) {
+ checkOpen();
+ final CollectionEntry ce = persistenceContext.getCollectionEntry( collection );
+ if ( ce == null ) {
+ throw new HibernateException( "no entry for collection" );
+ }
+ if ( collection.wasInitialized() ) {
+ return voidFuture();
+ }
+ else {
+ final ReactiveCollectionPersister loadedPersister =
+ (ReactiveCollectionPersister) ce.getLoadedPersister();
+ final Object loadedKey = ce.getLoadedKey();
+ if ( LOG.isTraceEnabled() ) {
+ LOG.trace( "Initializing collection "
+ + collectionInfoString( loadedPersister, collection, loadedKey, this ) );
+ }
+ final boolean foundInCache =
+ initializeCollectionFromCache( loadedKey, loadedPersister, collection, this );
+ if ( foundInCache ) {
+ LOG.trace( "Collection initialized from cache" );
+ return voidFuture();
+ }
+ else {
+ return loadedPersister.reactiveInitialize( loadedKey, this )
+ .thenAccept( v -> {
+ handlePotentiallyEmptyCollection( collection, persistenceContext, loadedKey, loadedPersister );
+ LOG.trace( "Collection initialized" );
+ final StatisticsImplementor statistics = getFactory().getStatistics();
+ if ( statistics.isStatisticsEnabled() ) {
+ statistics.fetchCollection( loadedPersister.getRole() );
+ }
+ } );
+ }
+ }
+ }
+
@Override
public CompletionStage reactiveFetch(T association, boolean unproxy) {
checkOpen();
diff --git a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/stage/Stage.java b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/stage/Stage.java
index 981c2b703..7219501bc 100644
--- a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/stage/Stage.java
+++ b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/stage/Stage.java
@@ -1806,15 +1806,6 @@ default CompletionStage refresh(Object entity, LockModeType lockModeType)
*/
CompletionStage upsert(Object entity);
- /**
- *
- * @param entityName The entityName for the entity to be merged
- * @param entity a detached entity instance
- *
- * @see org.hibernate.StatelessSession#upsert(String, Object)
- */
- CompletionStage upsert(String entityName, Object entity);
-
/**
* Use a SQL {@code merge into} statement to perform
* an upsert on multiple rows using the size of the given array
diff --git a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/stage/impl/StageSessionImpl.java b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/stage/impl/StageSessionImpl.java
index 32227de7b..da09a284b 100644
--- a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/stage/impl/StageSessionImpl.java
+++ b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/stage/impl/StageSessionImpl.java
@@ -19,8 +19,6 @@
import org.hibernate.reactive.common.ResultSetMapping;
import org.hibernate.reactive.engine.ReactiveActionQueue;
import org.hibernate.reactive.engine.spi.ReactiveSharedSessionContractImplementor;
-import org.hibernate.reactive.logging.impl.Log;
-import org.hibernate.reactive.logging.impl.LoggerFactory;
import org.hibernate.reactive.pool.ReactiveConnection;
import org.hibernate.reactive.query.ReactiveQuery;
import org.hibernate.reactive.session.ReactiveConnectionSupplier;
@@ -43,7 +41,6 @@
import jakarta.persistence.criteria.CriteriaQuery;
import jakarta.persistence.criteria.CriteriaUpdate;
import jakarta.persistence.metamodel.Attribute;
-import java.lang.invoke.MethodHandles;
import java.util.List;
import java.util.concurrent.CompletionStage;
import java.util.function.Function;
@@ -59,8 +56,6 @@
*/
public class StageSessionImpl implements Stage.Session {
- private static final Log LOG = LoggerFactory.make( Log.class, MethodHandles.lookup() );
-
private final ReactiveSession delegate;
public StageSessionImpl(ReactiveSession session) {
@@ -252,38 +247,22 @@ public CompletionStage lock(Object entity, LockOptions lockOptions) {
@Override
public FlushMode getFlushMode() {
- switch ( delegate.getHibernateFlushMode() ) {
- case MANUAL:
- return FlushMode.MANUAL;
- case COMMIT:
- return FlushMode.COMMIT;
- case AUTO:
- return FlushMode.AUTO;
- case ALWAYS:
- return FlushMode.ALWAYS;
- default:
- throw LOG.impossibleFlushModeIllegalState();
- }
+ return switch ( delegate.getHibernateFlushMode() ) {
+ case MANUAL -> FlushMode.MANUAL;
+ case COMMIT -> FlushMode.COMMIT;
+ case AUTO -> FlushMode.AUTO;
+ case ALWAYS -> FlushMode.ALWAYS;
+ };
}
@Override
public Stage.Session setFlushMode(FlushMode flushMode) {
- switch ( flushMode ) {
- case COMMIT:
- delegate.setHibernateFlushMode( org.hibernate.FlushMode.COMMIT );
- break;
- case AUTO:
- delegate.setHibernateFlushMode( org.hibernate.FlushMode.AUTO );
- break;
- case MANUAL:
- delegate.setHibernateFlushMode( org.hibernate.FlushMode.MANUAL );
- break;
- case ALWAYS:
- delegate.setHibernateFlushMode( org.hibernate.FlushMode.ALWAYS );
- break;
- default:
- throw new IllegalArgumentException( "Unsupported flushMode: " + flushMode );
- }
+ delegate.setHibernateFlushMode( switch ( flushMode ) {
+ case COMMIT -> org.hibernate.FlushMode.COMMIT;
+ case AUTO -> org.hibernate.FlushMode.AUTO;
+ case MANUAL -> org.hibernate.FlushMode.MANUAL;
+ case ALWAYS -> org.hibernate.FlushMode.ALWAYS;
+ } );
return this;
}
diff --git a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/stage/impl/StageStatelessSessionImpl.java b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/stage/impl/StageStatelessSessionImpl.java
index 4c325fdf9..07f7ef35a 100644
--- a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/stage/impl/StageStatelessSessionImpl.java
+++ b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/stage/impl/StageStatelessSessionImpl.java
@@ -154,11 +154,6 @@ public CompletionStage upsert(Object entity) {
return delegate.reactiveUpsert( entity );
}
- @Override
- public CompletionStage upsert(String entityName, Object entity) {
- return delegate.reactiveUpsert( entityName, entity );
- }
-
@Override
public CompletionStage upsertAll(Object... entities) {
return delegate.reactiveUpsertAll( entities.length, entities );
diff --git a/hibernate-reactive-core/src/test/java/org/hibernate/reactive/UpsertTest.java b/hibernate-reactive-core/src/test/java/org/hibernate/reactive/UpsertTest.java
index 52dc52a72..8dcc07a6a 100644
--- a/hibernate-reactive-core/src/test/java/org/hibernate/reactive/UpsertTest.java
+++ b/hibernate-reactive-core/src/test/java/org/hibernate/reactive/UpsertTest.java
@@ -104,34 +104,6 @@ public void testMutinyUpsert(VertxTestContext context) {
);
}
- @Test
- public void testMutinyUpsertWithEntityName(VertxTestContext context) {
- test( context, getMutinySessionFactory().withStatelessTransaction( ss -> ss
- .upsert( Record.class.getName(), new Record( 123L, "hello earth" ) )
- .call( () -> ss.upsert( Record.class.getName(), new Record( 456L, "hello mars" ) ) )
- .invoke( this::assertQueries )
- )
- .call( v -> getMutinySessionFactory().withStatelessTransaction( ss -> ss
- .createSelectionQuery( "from Record order by id", Record.class ).getResultList() )
- .invoke( results -> assertThat( results ).containsExactly(
- new Record( 123L, "hello earth" ),
- new Record( 456L, "hello mars" )
- ) )
- )
- .call( () -> getMutinySessionFactory().withStatelessTransaction( ss -> ss
- .upsert( Record.class.getName(), new Record( 123L, "goodbye earth" ) )
- ) )
- .invoke( this::assertQueries )
- .call( v -> getMutinySessionFactory().withStatelessTransaction( ss -> ss
- .createSelectionQuery( "from Record order by id", Record.class ).getResultList() )
- .invoke( results -> assertThat( results ).containsExactly(
- new Record( 123L, "goodbye earth" ),
- new Record( 456L, "hello mars" )
- ) )
- )
- );
- }
-
@Test
public void testStageUpsert(VertxTestContext context) {
test( context, getSessionFactory().withStatelessTransaction( ss -> ss
@@ -160,34 +132,6 @@ public void testStageUpsert(VertxTestContext context) {
);
}
- @Test
- public void testStageUpsertWithEntityName(VertxTestContext context) {
- test( context, getSessionFactory().withStatelessTransaction( ss -> ss
- .upsert( Record.class.getName(), new Record( 123L, "hello earth" ) )
- .thenCompose( v -> ss.upsert( Record.class.getName(), new Record( 456L, "hello mars" ) ) )
- )
- .thenAccept( v -> this.assertQueries() )
- .thenCompose( v -> getSessionFactory().withStatelessTransaction( ss -> ss
- .createSelectionQuery( "from Record order by id", Record.class ).getResultList() )
- .thenAccept( results -> assertThat( results ).containsExactly(
- new Record( 123L, "hello earth" ),
- new Record( 456L, "hello mars" )
- ) )
- )
- .thenCompose( v -> getSessionFactory().withStatelessTransaction( ss -> ss
- .upsert( Record.class.getName(), new Record( 123L, "goodbye earth" ) )
- ) )
- .thenAccept( v -> this.assertQueries() )
- .thenCompose( v -> getSessionFactory().withStatelessTransaction( ss -> ss
- .createSelectionQuery( "from Record order by id", Record.class ).getResultList() )
- .thenAccept( results -> assertThat( results ).containsExactly(
- new Record( 123L, "goodbye earth" ),
- new Record( 456L, "hello mars" )
- ) )
- )
- );
- }
-
private void assertQueries() {
if ( hasMergeOperator() ) {
assertThat( sqlTracker.getLoggedQueries() ).have( IS_USING_MERGE );