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 );