Repository: hibernate/hibernate-reactive
Pull request #2240 (2025-04-30 17:57:36)

[#2238] Delegators and getCurrentSession() for use in Quarkus (2.4)


Patch:
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 65b0ad90..90972f9c 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
@@ -2279,6 +2279,31 @@ default <T> Uni<T> withStatelessTransaction(Function<StatelessSession, Uni<T>> w
 		 */
 		Statistics getStatistics();
 
+		/**
+		 * Return the current instance of {@link Session}, if any.
+		 * A current session exists only when this method is called
+		 * from within an invocation of {@link #withSession(Function)}
+		 * or {@link #withTransaction(Function)}.
+		 *
+		 * @return the current instance, if any, or {@code null}
+		 *
+		 * @since 2.4.7
+		 */
+		Session getCurrentSession();
+
+		/**
+		 * Return the current instance of {@link Session}, if any.
+		 * A current session exists only when this method is called
+		 * from within an invocation of
+		 * {@link #withStatelessSession(Function)} or
+		 * {@link #withStatelessTransaction(Function)}.
+		 *
+		 * @return the current instance, if any, or {@code null}
+		 *
+		 * @since 2.4.7
+		 */
+		StatelessSession getCurrentStatelessSession();
+
 		/**
 		 * Destroy the session factory and clean up its connection pool.
 		 */
diff --git a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/mutiny/delegation/MutinySessionDelegator.java b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/mutiny/delegation/MutinySessionDelegator.java
new file mode 100644
index 00000000..09d85913
--- /dev/null
+++ b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/mutiny/delegation/MutinySessionDelegator.java
@@ -0,0 +1,341 @@
+/* Hibernate, Relational Persistence for Idiomatic Java
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * Copyright: Red Hat Inc. and Hibernate Authors
+ */
+package org.hibernate.reactive.mutiny.delegation;
+
+import io.smallrye.mutiny.Uni;
+import jakarta.persistence.CacheRetrieveMode;
+import jakarta.persistence.CacheStoreMode;
+import jakarta.persistence.EntityGraph;
+import jakarta.persistence.FlushModeType;
+import jakarta.persistence.LockModeType;
+import jakarta.persistence.criteria.CriteriaDelete;
+import jakarta.persistence.criteria.CriteriaQuery;
+import jakarta.persistence.criteria.CriteriaUpdate;
+import jakarta.persistence.metamodel.Attribute;
+import org.hibernate.CacheMode;
+import org.hibernate.Filter;
+import org.hibernate.FlushMode;
+import org.hibernate.Incubating;
+import org.hibernate.LockMode;
+import org.hibernate.reactive.common.AffectedEntities;
+import org.hibernate.reactive.common.Identifier;
+import org.hibernate.reactive.common.ResultSetMapping;
+import org.hibernate.reactive.mutiny.Mutiny;
+
+import java.util.List;
+import java.util.function.Function;
+
+/**
+ * Wraps a {@linkplain #delegate} session.
+ *
+ * @author Gavin King
+ */
+public abstract class MutinySessionDelegator implements Mutiny.Session {
+
+    public abstract Mutiny.Session delegate();
+
+    public <T> Uni<T> find(Class<T> entityClass, Object id) {
+        return delegate().find(entityClass, id);
+    }
+
+    public <T> Uni<T> find(Class<T> entityClass, Object id, LockModeType lockModeType) {
+        return delegate().find(entityClass, id, lockModeType);
+    }
+
+    public <T> Uni<T> find(Class<T> entityClass, Object id, LockMode lockMode) {
+        return delegate().find(entityClass, id, lockMode);
+    }
+
+    public <T> Uni<T> find(EntityGraph<T> entityGraph, Object id) {
+        return delegate().find(entityGraph, id);
+    }
+
+    public <T> Uni<List<T>> find(Class<T> entityClass, Object... ids) {
+        return delegate().find(entityClass, ids);
+    }
+
+    public <R> Mutiny.SelectionQuery<R> createNamedQuery(String queryName, Class<R> resultType) {
+        return delegate().createNamedQuery(queryName, resultType);
+    }
+
+    public <R> Mutiny.SelectionQuery<R> createQuery(String queryString, Class<R> resultType) {
+        return delegate().createQuery(queryString, resultType);
+    }
+
+    public boolean isReadOnly(Object entityOrProxy) {
+        return delegate().isReadOnly(entityOrProxy);
+    }
+
+    public <R> Mutiny.SelectionQuery<R> createNativeQuery(String queryString, Class<R> resultType, AffectedEntities affectedEntities) {
+        return delegate().createNativeQuery(queryString, resultType, affectedEntities);
+    }
+
+    public boolean isDefaultReadOnly() {
+        return delegate().isDefaultReadOnly();
+    }
+
+    public <T> Uni<T> unproxy(T association) {
+        return delegate().unproxy(association);
+    }
+
+    public Mutiny.MutationQuery createMutationQuery(String queryString) {
+        return delegate().createMutationQuery(queryString);
+    }
+
+    public Uni<Void> close() {
+        return delegate().close();
+    }
+
+    public Mutiny.Session disableFetchProfile(String name) {
+        return delegate().disableFetchProfile(name);
+    }
+
+    public <T> EntityGraph<T> getEntityGraph(Class<T> rootType, String graphName) {
+        return delegate().getEntityGraph(rootType, graphName);
+    }
+
+    public <R> Mutiny.SelectionQuery<R> createSelectionQuery(String queryString, Class<R> resultType) {
+        return delegate().createSelectionQuery(queryString, resultType);
+    }
+
+    public Uni<Void> refresh(Object entity, LockModeType lockModeType) {
+        return delegate().refresh(entity, lockModeType);
+    }
+
+    public Uni<Void> lock(Object entity, LockModeType lockModeType) {
+        return delegate().lock(entity, lockModeType);
+    }
+
+    public <R> Mutiny.SelectionQuery<R> createNativeQuery(String queryString, ResultSetMapping<R> resultSetMapping, AffectedEntities affectedEntities) {
+        return delegate().createNativeQuery(queryString, resultSetMapping, affectedEntities);
+    }
+
+    public Uni<Void> lock(Object entity, LockMode lockMode) {
+        return delegate().lock(entity, lockMode);
+    }
+
+    @Incubating
+    public <T> Uni<T> find(Class<T> entityClass, Identifier<T> naturalId) {
+        return delegate().find(entityClass, naturalId);
+    }
+
+    public <T> Uni<T> withTransaction(Function<Mutiny.Transaction, Uni<T>> work) {
+        return delegate().withTransaction(work);
+    }
+
+    public <R> Mutiny.SelectionQuery<R> createNativeQuery(String queryString, ResultSetMapping<R> resultSetMapping) {
+        return delegate().createNativeQuery(queryString, resultSetMapping);
+    }
+
+    public <T> EntityGraph<T> createEntityGraph(Class<T> rootType, String graphName) {
+        return delegate().createEntityGraph(rootType, graphName);
+    }
+
+    public Mutiny.Transaction currentTransaction() {
+        return delegate().currentTransaction();
+    }
+
+    public Mutiny.Session detach(Object entity) {
+        return delegate().detach(entity);
+    }
+
+    public Mutiny.Session setCacheStoreMode(CacheStoreMode cacheStoreMode) {
+        return delegate().setCacheStoreMode(cacheStoreMode);
+    }
+
+    public FlushMode getFlushMode() {
+        return delegate().getFlushMode();
+    }
+
+    public LockMode getLockMode(Object entity) {
+        return delegate().getLockMode(entity);
+    }
+
+    public <R> Mutiny.Query<R> createNamedQuery(String queryName) {
+        return delegate().createNamedQuery(queryName);
+    }
+
+    public Mutiny.SessionFactory getFactory() {
+        return delegate().getFactory();
+    }
+
+    public <R> Mutiny.SelectionQuery<R> createNativeQuery(String queryString, Class<R> resultType) {
+        return delegate().createNativeQuery(queryString, resultType);
+    }
+
+    public Mutiny.Session setSubselectFetchingEnabled(boolean enabled) {
+        return delegate().setSubselectFetchingEnabled(enabled);
+    }
+
+    public Mutiny.Session setFlushMode(FlushMode flushMode) {
+        return delegate().setFlushMode(flushMode);
+    }
+
+    public Uni<Void> remove(Object entity) {
+        return delegate().remove(entity);
+    }
+
+    public Mutiny.Session setCacheMode(CacheMode cacheMode) {
+        return delegate().setCacheMode(cacheMode);
+    }
+
+    public Filter enableFilter(String filterName) {
+        return delegate().enableFilter(filterName);
+    }
+
+    public <R> Mutiny.Query<R> createNativeQuery(String queryString, AffectedEntities affectedEntities) {
+        return delegate().createNativeQuery(queryString, affectedEntities);
+    }
+
+    public Mutiny.Session setReadOnly(Object entityOrProxy, boolean readOnly) {
+        return delegate().setReadOnly(entityOrProxy, readOnly);
+    }
+
+    public <T> EntityGraph<T> createEntityGraph(Class<T> rootType) {
+        return delegate().createEntityGraph(rootType);
+    }
+
+    public Uni<Void> refreshAll(Object... entities) {
+        return delegate().refreshAll(entities);
+    }
+
+    public Integer getBatchSize() {
+        return delegate().getBatchSize();
+    }
+
+    public Uni<Void> refresh(Object entity, LockMode lockMode) {
+        return delegate().refresh(entity, lockMode);
+    }
+
+    public <T> T getReference(Class<T> entityClass, Object id) {
+        return delegate().getReference(entityClass, id);
+    }
+
+    public <T> T getReference(T entity) {
+        return delegate().getReference(entity);
+    }
+
+    public Mutiny.Session setBatchSize(Integer batchSize) {
+        return delegate().setBatchSize(batchSize);
+    }
+
+    public Uni<Void> refresh(Object entity) {
+        return delegate().refresh(entity);
+    }
+
+    public CacheMode getCacheMode() {
+        return delegate().getCacheMode();
+    }
+
+    public Uni<Void> mergeAll(Object... entities) {
+        return delegate().mergeAll(entities);
+    }
+
+    public Uni<Void> persist(Object object) {
+        return delegate().persist(object);
+    }
+
+    public boolean contains(Object entity) {
+        return delegate().contains(entity);
+    }
+
+    public int getFetchBatchSize() {
+        return delegate().getFetchBatchSize();
+    }
+
+    public Mutiny.Session setDefaultReadOnly(boolean readOnly) {
+        return delegate().setDefaultReadOnly(readOnly);
+    }
+
+    public Mutiny.Session clear() {
+        return delegate().clear();
+    }
+
+    public <E, T> Uni<T> fetch(E entity, Attribute<E, T> field) {
+        return delegate().fetch(entity, field);
+    }
+
+    public <R> Mutiny.SelectionQuery<R> createQuery(CriteriaQuery<R> criteriaQuery) {
+        return delegate().createQuery(criteriaQuery);
+    }
+
+    public Mutiny.Session setCacheRetrieveMode(CacheRetrieveMode cacheRetrieveMode) {
+        return delegate().setCacheRetrieveMode(cacheRetrieveMode);
+    }
+
+    public Uni<Void> removeAll(Object... entities) {
+        return delegate().removeAll(entities);
+    }
+
+    public Filter getEnabledFilter(String filterName) {
+        return delegate().getEnabledFilter(filterName);
+    }
+
+    public void disableFilter(String filterName) {
+        delegate().disableFilter(filterName);
+    }
+
+    public <R> Mutiny.MutationQuery createQuery(CriteriaDelete<R> criteriaDelete) {
+        return delegate().createQuery(criteriaDelete);
+    }
+
+    public Mutiny.Session enableFetchProfile(String name) {
+        return delegate().enableFetchProfile(name);
+    }
+
+    public <T> ResultSetMapping<T> getResultSetMapping(Class<T> resultType, String mappingName) {
+        return delegate().getResultSetMapping(resultType, mappingName);
+    }
+
+    public Uni<Void> flush() {
+        return delegate().flush();
+    }
+
+    public <R> Mutiny.Query<R> createNativeQuery(String queryString) {
+        return delegate().createNativeQuery(queryString);
+    }
+
+    public boolean isFetchProfileEnabled(String name) {
+        return delegate().isFetchProfileEnabled(name);
+    }
+
+    public <T> Uni<T> merge(T entity) {
+        return delegate().merge(entity);
+    }
+
+    public boolean isSubselectFetchingEnabled() {
+        return delegate().isSubselectFetchingEnabled();
+    }
+
+    public <R> Mutiny.MutationQuery createQuery(CriteriaUpdate<R> criteriaUpdate) {
+        return delegate().createQuery(criteriaUpdate);
+    }
+
+    public Mutiny.Session setFetchBatchSize(int batchSize) {
+        return delegate().setFetchBatchSize(batchSize);
+    }
+
+    public <T> Uni<T> fetch(T association) {
+        return delegate().fetch(association);
+    }
+
+    public Uni<Void> persistAll(Object... entities) {
+        return delegate().persistAll(entities);
+    }
+
+    @Deprecated
+    public <R> Mutiny.Query<R> createQuery(String queryString) {
+        return delegate().createQuery(queryString);
+    }
+
+    public Mutiny.Session setFlushMode(FlushModeType flushModeType) {
+        return delegate().setFlushMode(flushModeType);
+    }
+
+    public boolean isOpen() {
+        return delegate().isOpen();
+    }
+}
diff --git a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/mutiny/delegation/MutinyStatelessSessionDelegator.java b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/mutiny/delegation/MutinyStatelessSessionDelegator.java
new file mode 100644
index 00000000..15214000
--- /dev/null
+++ b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/mutiny/delegation/MutinyStatelessSessionDelegator.java
@@ -0,0 +1,191 @@
+/* Hibernate, Relational Persistence for Idiomatic Java
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * Copyright: Red Hat Inc. and Hibernate Authors
+ */
+package org.hibernate.reactive.mutiny.delegation;
+
+import io.smallrye.mutiny.Uni;
+import jakarta.persistence.EntityGraph;
+import jakarta.persistence.LockModeType;
+import jakarta.persistence.criteria.CriteriaQuery;
+import org.hibernate.Incubating;
+import org.hibernate.LockMode;
+import org.hibernate.reactive.common.ResultSetMapping;
+import org.hibernate.reactive.mutiny.Mutiny;
+
+import java.util.function.Function;
+
+/**
+ * Wraps a {@linkplain #delegate} stateless session.
+ *
+ * @author Gavin King
+ */
+public abstract class MutinyStatelessSessionDelegator implements Mutiny.StatelessSession {
+
+    public abstract Mutiny.StatelessSession delegate();
+
+    public <T> Uni<T> get(Class<T> entityClass, Object id) {
+        return delegate().get(entityClass, id);
+    }
+
+    @Deprecated
+    public <R> Mutiny.Query<R> createQuery(String queryString) {
+        return delegate().createQuery(queryString);
+    }
+
+    public <T> Uni<T> get(EntityGraph<T> entityGraph, Object id) {
+        return delegate().get(entityGraph, id);
+    }
+
+    public <R> Mutiny.SelectionQuery<R> createNativeQuery(String queryString, ResultSetMapping<R> resultSetMapping) {
+        return delegate().createNativeQuery(queryString, resultSetMapping);
+    }
+
+    public <T> Uni<T> get(Class<T> entityClass, Object id, LockMode lockMode) {
+        return delegate().get(entityClass, id, lockMode);
+    }
+
+    public boolean isOpen() {
+        return delegate().isOpen();
+    }
+
+    public Uni<Void> insertAll(Object... entities) {
+        return delegate().insertAll(entities);
+    }
+
+    public Uni<Void> updateAll(int batchSize, Object... entities) {
+        return delegate().updateAll(batchSize, entities);
+    }
+
+    public <T> EntityGraph<T> createEntityGraph(Class<T> rootType, String graphName) {
+        return delegate().createEntityGraph(rootType, graphName);
+    }
+
+    public <T> EntityGraph<T> getEntityGraph(Class<T> rootType, String graphName) {
+        return delegate().getEntityGraph(rootType, graphName);
+    }
+
+    public <T> Uni<T> get(Class<T> entityClass, Object id, LockModeType lockModeType) {
+        return delegate().get(entityClass, id, lockModeType);
+    }
+
+    public Uni<Void> update(Object entity) {
+        return delegate().update(entity);
+    }
+
+    public Uni<Void> refreshAll(int batchSize, Object... entities) {
+        return delegate().refreshAll(batchSize, entities);
+    }
+
+    public <R> Mutiny.SelectionQuery<R> createQuery(String queryString, Class<R> resultType) {
+        return delegate().createQuery(queryString, resultType);
+    }
+
+    public Uni<Void> delete(Object entity) {
+        return delegate().delete(entity);
+    }
+
+    public Uni<Void> refresh(Object entity, LockModeType lockModeType) {
+        return delegate().refresh(entity, lockModeType);
+    }
+
+    public Mutiny.SessionFactory getFactory() {
+        return delegate().getFactory();
+    }
+
+    public <R> Mutiny.SelectionQuery<R> createNativeQuery(String queryString, Class<R> resultType) {
+        return delegate().createNativeQuery(queryString, resultType);
+    }
+
+    public Uni<Void> deleteAll(Object... entities) {
+        return delegate().deleteAll(entities);
+    }
+
+    public <R> Mutiny.SelectionQuery<R> createSelectionQuery(String queryString, Class<R> resultType) {
+        return delegate().createSelectionQuery(queryString, resultType);
+    }
+
+    @Incubating
+    public Uni<Void> upsert(Object entity) {
+        return delegate().upsert(entity);
+    }
+
+    public Mutiny.MutationQuery createMutationQuery(String queryString) {
+        return delegate().createMutationQuery(queryString);
+    }
+
+    public Uni<Void> refresh(Object entity) {
+        return delegate().refresh(entity);
+    }
+
+    public <T> ResultSetMapping<T> getResultSetMapping(Class<T> resultType, String mappingName) {
+        return delegate().getResultSetMapping(resultType, mappingName);
+    }
+
+    public Uni<Void> insertAll(int batchSize, Object... entities) {
+        return delegate().insertAll(batchSize, entities);
+    }
+
+    public <R> Mutiny.Query<R> createNativeQuery(String queryString) {
+        return delegate().createNativeQuery(queryString);
+    }
+
+    public <R> Mutiny.Query<R> createNamedQuery(String queryName) {
+        return delegate().createNamedQuery(queryName);
+    }
+
+    public <R> Mutiny.SelectionQuery<R> createNamedQuery(String queryName, Class<R> resultType) {
+        return delegate().createNamedQuery(queryName, resultType);
+    }
+
+    public Uni<Void> refreshAll(Object... entities) {
+        return delegate().refreshAll(entities);
+    }
+
+    public Uni<Void> close() {
+        return delegate().close();
+    }
+
+    public Uni<Void> updateAll(Object... entities) {
+        return delegate().updateAll(entities);
+    }
+
+    public <R> Mutiny.SelectionQuery<R> createQuery(CriteriaQuery<R> criteriaQuery) {
+        return delegate().createQuery(criteriaQuery);
+    }
+
+    public <T> Uni<T> withTransaction(Function<Mutiny.Transaction, Uni<T>> work) {
+        return delegate().withTransaction(work);
+    }
+
+    public <T> Uni<T> fetch(T association) {
+        return delegate().fetch(association);
+    }
+
+    @Incubating
+    public Uni<Void> upsert(String entityName, Object entity) {
+        return delegate().upsert(entityName, entity);
+    }
+
+    @Incubating
+    public Mutiny.Transaction currentTransaction() {
+        return delegate().currentTransaction();
+    }
+
+    public <T> EntityGraph<T> createEntityGraph(Class<T> rootType) {
+        return delegate().createEntityGraph(rootType);
+    }
+
+    public Uni<Void> insert(Object entity) {
+        return delegate().insert(entity);
+    }
+
+    public Uni<Void> refresh(Object entity, LockMode lockMode) {
+        return delegate().refresh(entity, lockMode);
+    }
+
+    public Uni<Void> deleteAll(int batchSize, Object... entities) {
+        return delegate().deleteAll(batchSize, entities);
+    }
+}
diff --git a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/mutiny/impl/MutinySessionFactoryImpl.java b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/mutiny/impl/MutinySessionFactoryImpl.java
index aecc99e3..23feaba5 100644
--- a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/mutiny/impl/MutinySessionFactoryImpl.java
+++ b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/mutiny/impl/MutinySessionFactoryImpl.java
@@ -148,6 +148,16 @@ private CompletionStage<ReactiveConnection> connection(String tenantId) {
 				: connectionPool.getConnection( tenantId );
 	}
 
+	@Override
+	public Mutiny.Session getCurrentSession() {
+		return context.get( contextKeyForSession );
+	}
+
+	@Override
+	public Mutiny.StatelessSession getCurrentStatelessSession() {
+		return context.get( contextKeyForStatelessSession );
+	}
+
 	@Override
 	public <T> Uni<T> withSession(Function<Mutiny.Session, Uni<T>> work) {
 		Objects.requireNonNull( work, "parameter 'work' is required" );
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 47da9f6c..3a6164a3 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
@@ -2314,6 +2314,31 @@ default <T> CompletionStage<T> withStatelessTransaction(Function<StatelessSessio
 		 */
 		Statistics getStatistics();
 
+		/**
+		 * Return the current instance of {@link Session}, if any.
+		 * A current session exists only when this method is called
+		 * from within an invocation of {@link #withSession(Function)}
+		 * or {@link #withTransaction(Function)}.
+		 *
+		 * @return the current instance, if any, or {@code null}
+		 *
+		 * @since 2.4.7
+		 */
+		Session getCurrentSession();
+
+		/**
+		 * Return the current instance of {@link Session}, if any.
+		 * A current session exists only when this method is called
+		 * from within an invocation of
+		 * {@link #withStatelessSession(Function)} or
+		 * {@link #withStatelessTransaction(Function)}.
+		 *
+		 * @return the current instance, if any, or {@code null}
+		 *
+		 * @since 2.4.7
+		 */
+		StatelessSession getCurrentStatelessSession();
+
 		/**
 		 * Destroy the session factory and clean up its connection pool.
 		 */
diff --git a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/stage/impl/StageSessionFactoryImpl.java b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/stage/impl/StageSessionFactoryImpl.java
index b03df1fc..2c359192 100644
--- a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/stage/impl/StageSessionFactoryImpl.java
+++ b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/stage/impl/StageSessionFactoryImpl.java
@@ -138,6 +138,16 @@ private CompletionStage<ReactiveConnection> connection(String tenantId) {
 				: connectionPool.getConnection( tenantId );
 	}
 
+	@Override
+	public Stage.Session getCurrentSession() {
+		return context.get( contextKeyForSession );
+	}
+
+	@Override
+	public Stage.StatelessSession getCurrentStatelessSession() {
+		return context.get( contextKeyForStatelessSession );
+	}
+
 	@Override
 	public <T> CompletionStage<T> withSession(Function<Stage.Session, CompletionStage<T>> work) {
 		Objects.requireNonNull( work, "parameter 'work' is required" );


Test patch:
diff --git a/hibernate-reactive-core/src/test/java/org/hibernate/reactive/delegation/ConcreteSessionDelegator.java b/hibernate-reactive-core/src/test/java/org/hibernate/reactive/delegation/ConcreteSessionDelegator.java
new file mode 100644
index 00000000..2c93d922
--- /dev/null
+++ b/hibernate-reactive-core/src/test/java/org/hibernate/reactive/delegation/ConcreteSessionDelegator.java
@@ -0,0 +1,17 @@
+/* Hibernate, Relational Persistence for Idiomatic Java
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * Copyright: Red Hat Inc. and Hibernate Authors
+ */
+package org.hibernate.reactive.delegation;
+
+import org.hibernate.reactive.mutiny.Mutiny;
+import org.hibernate.reactive.mutiny.delegation.MutinySessionDelegator;
+
+@SuppressWarnings("unused")
+class ConcreteSessionDelegator extends MutinySessionDelegator {
+    @Override
+    public Mutiny.Session delegate() {
+        throw new UnsupportedOperationException();
+    }
+}
diff --git a/hibernate-reactive-core/src/test/java/org/hibernate/reactive/delegation/ConcreteStatelessSessionDelegator.java b/hibernate-reactive-core/src/test/java/org/hibernate/reactive/delegation/ConcreteStatelessSessionDelegator.java
new file mode 100644
index 00000000..e275d018
--- /dev/null
+++ b/hibernate-reactive-core/src/test/java/org/hibernate/reactive/delegation/ConcreteStatelessSessionDelegator.java
@@ -0,0 +1,17 @@
+/* Hibernate, Relational Persistence for Idiomatic Java
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * Copyright: Red Hat Inc. and Hibernate Authors
+ */
+package org.hibernate.reactive.delegation;
+
+import org.hibernate.reactive.mutiny.Mutiny;
+import org.hibernate.reactive.mutiny.delegation.MutinyStatelessSessionDelegator;
+
+@SuppressWarnings("unused")
+class ConcreteStatelessSessionDelegator extends MutinyStatelessSessionDelegator {
+    @Override
+    public Mutiny.StatelessSession delegate() {
+        throw new UnsupportedOperationException();
+    }
+}