diff --git a/hibernate-core/src/main/java/org/hibernate/boot/internal/SessionFactoryOptionsBuilder.java b/hibernate-core/src/main/java/org/hibernate/boot/internal/SessionFactoryOptionsBuilder.java index c17b283832bb..641d9607d157 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/internal/SessionFactoryOptionsBuilder.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/internal/SessionFactoryOptionsBuilder.java @@ -901,7 +901,7 @@ public boolean isAllowOutOfTransactionUpdateOperations() { } - @Override + @Override @Deprecated(forRemoval = true) public boolean isReleaseResourcesOnCloseEnabled() { return releaseResourcesOnCloseEnabled; } diff --git a/hibernate-core/src/main/java/org/hibernate/engine/creation/internal/CommonSharedSessionCreationOptions.java b/hibernate-core/src/main/java/org/hibernate/engine/creation/internal/CommonSharedSessionCreationOptions.java index 03260144be35..f3c40c49c058 100644 --- a/hibernate-core/src/main/java/org/hibernate/engine/creation/internal/CommonSharedSessionCreationOptions.java +++ b/hibernate-core/src/main/java/org/hibernate/engine/creation/internal/CommonSharedSessionCreationOptions.java @@ -8,6 +8,7 @@ import org.hibernate.Interceptor; import org.hibernate.Transaction; import org.hibernate.engine.jdbc.spi.JdbcCoordinator; +import org.hibernate.engine.spi.TransactionCompletionCallbacksImplementor; import org.hibernate.resource.jdbc.spi.PhysicalConnectionHandlingMode; import org.hibernate.resource.jdbc.spi.StatementInspector; import org.hibernate.resource.transaction.spi.TransactionCoordinator; @@ -43,6 +44,7 @@ public interface CommonSharedSessionCreationOptions { boolean isTransactionCoordinatorShared(); TransactionCoordinator getTransactionCoordinator(); JdbcCoordinator getJdbcCoordinator(); + TransactionCompletionCallbacksImplementor getTransactionCompletionCallbacksImplementor(); Transaction getTransaction(); TimeZone getJdbcTimeZone(); diff --git a/hibernate-core/src/main/java/org/hibernate/engine/creation/internal/SessionCreationOptionsAdaptor.java b/hibernate-core/src/main/java/org/hibernate/engine/creation/internal/SessionCreationOptionsAdaptor.java index 47692b72bd46..491755c0bd71 100644 --- a/hibernate-core/src/main/java/org/hibernate/engine/creation/internal/SessionCreationOptionsAdaptor.java +++ b/hibernate-core/src/main/java/org/hibernate/engine/creation/internal/SessionCreationOptionsAdaptor.java @@ -9,9 +9,9 @@ import org.hibernate.Interceptor; import org.hibernate.SessionEventListener; import org.hibernate.Transaction; -import org.hibernate.engine.internal.TransactionCompletionCallbacksImpl; import org.hibernate.engine.jdbc.spi.JdbcCoordinator; import org.hibernate.engine.spi.SessionFactoryImplementor; +import org.hibernate.engine.spi.TransactionCompletionCallbacksImplementor; import org.hibernate.resource.jdbc.spi.PhysicalConnectionHandlingMode; import org.hibernate.resource.jdbc.spi.StatementInspector; import org.hibernate.resource.transaction.spi.TransactionCoordinator; @@ -140,7 +140,7 @@ public Transaction getTransaction() { } @Override - public TransactionCompletionCallbacksImpl getTransactionCompletionCallbacks() { - return null; + public TransactionCompletionCallbacksImplementor getTransactionCompletionCallbacks() { + return options.getTransactionCompletionCallbacksImplementor(); } } diff --git a/hibernate-core/src/main/java/org/hibernate/engine/creation/internal/SharedSessionBuilderImpl.java b/hibernate-core/src/main/java/org/hibernate/engine/creation/internal/SharedSessionBuilderImpl.java index ecf9977dc6c2..2c8328111cdf 100644 --- a/hibernate-core/src/main/java/org/hibernate/engine/creation/internal/SharedSessionBuilderImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/engine/creation/internal/SharedSessionBuilderImpl.java @@ -12,10 +12,10 @@ import org.hibernate.SessionException; import org.hibernate.Transaction; import org.hibernate.engine.creation.spi.SharedSessionBuilderImplementor; -import org.hibernate.engine.internal.TransactionCompletionCallbacksImpl; import org.hibernate.engine.jdbc.spi.JdbcCoordinator; import org.hibernate.engine.spi.SessionImplementor; import org.hibernate.engine.spi.SharedSessionContractImplementor; +import org.hibernate.engine.spi.TransactionCompletionCallbacksImplementor; import org.hibernate.internal.CoreLogging; import org.hibernate.resource.jdbc.spi.PhysicalConnectionHandlingMode; import org.hibernate.resource.jdbc.spi.StatementInspector; @@ -277,6 +277,14 @@ public Transaction getTransaction() { : null; } + @Override + public TransactionCompletionCallbacksImplementor getTransactionCompletionCallbacks() { + return shareTransactionContext + ? original.getTransactionCompletionCallbacksImplementor() + : null; + } + + // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // CommonSharedSessionCreationOptions @@ -309,11 +317,6 @@ public CacheMode getInitialCacheMode() { // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // SharedSessionCreationOptions - @Override - public TransactionCompletionCallbacksImpl getTransactionCompletionCallbacks() { - return null; - } - @Override public boolean shouldAutoJoinTransactions() { return autoJoinTransactions; diff --git a/hibernate-core/src/main/java/org/hibernate/engine/creation/internal/SharedSessionCreationOptions.java b/hibernate-core/src/main/java/org/hibernate/engine/creation/internal/SharedSessionCreationOptions.java index c7452d0b7d3e..4cfd6ad693f8 100644 --- a/hibernate-core/src/main/java/org/hibernate/engine/creation/internal/SharedSessionCreationOptions.java +++ b/hibernate-core/src/main/java/org/hibernate/engine/creation/internal/SharedSessionCreationOptions.java @@ -5,8 +5,8 @@ package org.hibernate.engine.creation.internal; import org.hibernate.Transaction; -import org.hibernate.engine.internal.TransactionCompletionCallbacksImpl; import org.hibernate.engine.jdbc.spi.JdbcCoordinator; +import org.hibernate.engine.spi.TransactionCompletionCallbacksImplementor; import org.hibernate.resource.transaction.spi.TransactionCoordinator; /** @@ -25,5 +25,5 @@ public interface SharedSessionCreationOptions extends SessionCreationOptions { TransactionCoordinator getTransactionCoordinator(); JdbcCoordinator getJdbcCoordinator(); Transaction getTransaction(); - TransactionCompletionCallbacksImpl getTransactionCompletionCallbacks(); + TransactionCompletionCallbacksImplementor getTransactionCompletionCallbacks(); } diff --git a/hibernate-core/src/main/java/org/hibernate/engine/creation/internal/SharedStatelessSessionBuilderImpl.java b/hibernate-core/src/main/java/org/hibernate/engine/creation/internal/SharedStatelessSessionBuilderImpl.java index da6973768ca8..3e4b31d94c6c 100644 --- a/hibernate-core/src/main/java/org/hibernate/engine/creation/internal/SharedStatelessSessionBuilderImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/engine/creation/internal/SharedStatelessSessionBuilderImpl.java @@ -14,6 +14,7 @@ import org.hibernate.engine.jdbc.spi.JdbcCoordinator; import org.hibernate.engine.spi.SharedSessionContractImplementor; import org.hibernate.engine.spi.StatelessSessionImplementor; +import org.hibernate.engine.spi.TransactionCompletionCallbacksImplementor; import org.hibernate.internal.CoreLogging; import org.hibernate.resource.jdbc.spi.PhysicalConnectionHandlingMode; import org.hibernate.resource.jdbc.spi.StatementInspector; @@ -167,6 +168,13 @@ public JdbcCoordinator getJdbcCoordinator() { : null; } + @Override + public TransactionCompletionCallbacksImplementor getTransactionCompletionCallbacksImplementor() { + return shareTransactionContext + ? original.getTransactionCompletionCallbacksImplementor() + : null; + } + @Override public Transaction getTransaction() { return shareTransactionContext diff --git a/hibernate-core/src/main/java/org/hibernate/engine/internal/TransactionCompletionCallbacksImpl.java b/hibernate-core/src/main/java/org/hibernate/engine/internal/TransactionCompletionCallbacksImpl.java index 4499b55ee1b2..4f6d70a44ba5 100644 --- a/hibernate-core/src/main/java/org/hibernate/engine/internal/TransactionCompletionCallbacksImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/engine/internal/TransactionCompletionCallbacksImpl.java @@ -5,12 +5,12 @@ package org.hibernate.engine.internal; import org.hibernate.engine.spi.SharedSessionContractImplementor; -import org.hibernate.engine.spi.TransactionCompletionCallbacks; +import org.hibernate.engine.spi.TransactionCompletionCallbacksImplementor; /** * @author Steve Ebersole */ -public class TransactionCompletionCallbacksImpl implements TransactionCompletionCallbacks { +public class TransactionCompletionCallbacksImpl implements TransactionCompletionCallbacksImplementor { private final SharedSessionContractImplementor session; private BeforeTransactionCompletionProcessQueue beforeTransactionProcesses; @@ -28,11 +28,13 @@ public void registerCallback(BeforeCompletionCallback process) { beforeTransactionProcesses.register( process ); } + @Override public boolean hasBeforeCompletionCallbacks() { return beforeTransactionProcesses != null && beforeTransactionProcesses.hasActions(); } + @Override public void beforeTransactionCompletion() { if ( beforeTransactionProcesses != null && beforeTransactionProcesses.hasActions() ) { beforeTransactionProcesses.beforeTransactionCompletion(); @@ -47,23 +49,27 @@ public void registerCallback(AfterCompletionCallback process) { afterTransactionProcesses.register( process ); } + @Override public boolean hasAfterCompletionCallbacks() { return afterTransactionProcesses != null && afterTransactionProcesses.hasActions(); } + @Override public void afterTransactionCompletion(boolean success) { if ( afterTransactionProcesses != null && afterTransactionProcesses.hasActions() ) { afterTransactionProcesses.afterTransactionCompletion( success ); } } + @Override public void addSpaceToInvalidate(String space) { if ( afterTransactionProcesses == null ) { afterTransactionProcesses = new AfterTransactionCompletionProcessQueue( session ); } afterTransactionProcesses.addSpaceToInvalidate( space ); -} + } + @Override public TransactionCompletionCallbacksImpl forSharing() { if ( beforeTransactionProcesses == null ) { beforeTransactionProcesses = new BeforeTransactionCompletionProcessQueue( session ); diff --git a/hibernate-core/src/main/java/org/hibernate/engine/spi/ActionQueue.java b/hibernate-core/src/main/java/org/hibernate/engine/spi/ActionQueue.java index 432d0dcdc639..38bd16fe5319 100644 --- a/hibernate-core/src/main/java/org/hibernate/engine/spi/ActionQueue.java +++ b/hibernate-core/src/main/java/org/hibernate/engine/spi/ActionQueue.java @@ -95,7 +95,7 @@ public class ActionQueue implements TransactionCompletionCallbacks { private transient boolean isTransactionCoordinatorShared; - private TransactionCompletionCallbacksImpl transactionCompletionCallbacks;; + private TransactionCompletionCallbacksImplementor transactionCompletionCallbacks;; // Extract this as a constant to perform efficient iterations: // method values() otherwise allocates a new array on each invocation. @@ -725,7 +725,7 @@ public int numberOfInsertions() { return insertions == null ? 0 : insertions.size(); } - public TransactionCompletionCallbacksImpl getTransactionCompletionCallbacks() { + public TransactionCompletionCallbacksImplementor getTransactionCompletionCallbacks() { return transactionCompletionCallbacks.forSharing(); } @@ -738,7 +738,7 @@ public TransactionCompletionCallbacksImpl getTransactionCompletionCallbacks() { * @param isTransactionCoordinatorShared Flag indicating shared transaction context. */ public void setTransactionCompletionCallbacks( - TransactionCompletionCallbacksImpl callbacks, + TransactionCompletionCallbacksImplementor callbacks, boolean isTransactionCoordinatorShared) { this.isTransactionCoordinatorShared = isTransactionCoordinatorShared; this.transactionCompletionCallbacks = callbacks; diff --git a/hibernate-core/src/main/java/org/hibernate/engine/spi/SessionDelegatorBaseImpl.java b/hibernate-core/src/main/java/org/hibernate/engine/spi/SessionDelegatorBaseImpl.java index 90c3b1c3e636..d66c9cc18f6c 100644 --- a/hibernate-core/src/main/java/org/hibernate/engine/spi/SessionDelegatorBaseImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/engine/spi/SessionDelegatorBaseImpl.java @@ -1175,6 +1175,11 @@ public TransactionCompletionCallbacks getTransactionCompletionCallbacks() { return delegate.getTransactionCompletionCallbacks(); } + @Override + public TransactionCompletionCallbacksImplementor getTransactionCompletionCallbacksImplementor() { + return delegate.getTransactionCompletionCallbacksImplementor(); + } + @Override public Object instantiate(EntityPersister persister, Object id) throws HibernateException { return delegate.instantiate( persister, id ); diff --git a/hibernate-core/src/main/java/org/hibernate/engine/spi/SessionImplementor.java b/hibernate-core/src/main/java/org/hibernate/engine/spi/SessionImplementor.java index 084e35f01db5..5dd68770d060 100644 --- a/hibernate-core/src/main/java/org/hibernate/engine/spi/SessionImplementor.java +++ b/hibernate-core/src/main/java/org/hibernate/engine/spi/SessionImplementor.java @@ -78,6 +78,11 @@ default TransactionCompletionCallbacks getTransactionCompletionCallbacks() { return getActionQueue(); } + @Override + default TransactionCompletionCallbacksImplementor getTransactionCompletionCallbacksImplementor() { + return getActionQueue().getTransactionCompletionCallbacks(); + } + /** * Should this session be automatically closed after the current * transaction completes? diff --git a/hibernate-core/src/main/java/org/hibernate/engine/spi/SharedSessionContractImplementor.java b/hibernate-core/src/main/java/org/hibernate/engine/spi/SharedSessionContractImplementor.java index dba79234c803..b441357630f2 100644 --- a/hibernate-core/src/main/java/org/hibernate/engine/spi/SharedSessionContractImplementor.java +++ b/hibernate-core/src/main/java/org/hibernate/engine/spi/SharedSessionContractImplementor.java @@ -264,6 +264,14 @@ default void checkTransactionNeededForUpdateOperation(String exceptionMessage) { @Incubating TransactionCompletionCallbacks getTransactionCompletionCallbacks(); + /** + * Access to registered callbacks for transaction completion processing. + * + * @since 7.2 + */ + @Incubating + TransactionCompletionCallbacksImplementor getTransactionCompletionCallbacksImplementor(); + /** * Instantiate an {@link EntityKey} with the given id and for the * entity represented by the given {@link EntityPersister}. diff --git a/hibernate-core/src/main/java/org/hibernate/engine/spi/SharedSessionDelegatorBaseImpl.java b/hibernate-core/src/main/java/org/hibernate/engine/spi/SharedSessionDelegatorBaseImpl.java index 2b709017cc41..5a9893154c61 100644 --- a/hibernate-core/src/main/java/org/hibernate/engine/spi/SharedSessionDelegatorBaseImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/engine/spi/SharedSessionDelegatorBaseImpl.java @@ -732,4 +732,9 @@ public Transaction getCurrentTransaction() { public SharedSessionBuilder sessionWithOptions() { return delegate.sessionWithOptions(); } + + @Override + public TransactionCompletionCallbacksImplementor getTransactionCompletionCallbacksImplementor() { + return delegate.getTransactionCompletionCallbacksImplementor(); + } } diff --git a/hibernate-core/src/main/java/org/hibernate/engine/spi/TransactionCompletionCallbacksImplementor.java b/hibernate-core/src/main/java/org/hibernate/engine/spi/TransactionCompletionCallbacksImplementor.java new file mode 100644 index 000000000000..10eb8e98cc29 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/engine/spi/TransactionCompletionCallbacksImplementor.java @@ -0,0 +1,47 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * Copyright Red Hat Inc. and Hibernate Authors + */ +package org.hibernate.engine.spi; + +import org.hibernate.Incubating; + +/** + * @since 7.2 + * + * @author Gavin King + * + */ +@Incubating // is this separate interface really needed? +public interface TransactionCompletionCallbacksImplementor extends TransactionCompletionCallbacks { + /** + * Are there any registered before-completion callbacks? + */ + boolean hasBeforeCompletionCallbacks(); + + /** + * Are there any registered after-completion callbacks? + */ + boolean hasAfterCompletionCallbacks(); + + /** + * Execute registered before-completion callbacks, if any. + */ + void beforeTransactionCompletion(); + + /** + * Execute registered after-completion callbacks, if any. + */ + void afterTransactionCompletion(boolean success); + + /** + * Register a cache space to be invalidated after successful transaction completion. + */ + void addSpaceToInvalidate(String space); + + /** + * Ensure internal queues are initialized for sharing between sessions that share + * the same transaction coordinator. Returns this instance for convenience/fluency. + */ + TransactionCompletionCallbacksImplementor forSharing(); +} diff --git a/hibernate-core/src/main/java/org/hibernate/internal/SessionFactoryImpl.java b/hibernate-core/src/main/java/org/hibernate/internal/SessionFactoryImpl.java index 7a620506ccf0..89008771e595 100644 --- a/hibernate-core/src/main/java/org/hibernate/internal/SessionFactoryImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/internal/SessionFactoryImpl.java @@ -546,7 +546,7 @@ public SessionBuilderImplementor withOptions() { return new SessionBuilderImpl( this ) { @Override protected SessionImplementor createSession() { - return new SessionImpl( (SessionFactoryImpl) sessionFactory, this ); + return new SessionImpl( SessionFactoryImpl.this, this ); } }; } @@ -556,7 +556,7 @@ public StatelessSessionBuilder withStatelessOptions() { return new StatelessSessionBuilderImpl( this ) { @Override protected StatelessSessionImplementor createStatelessSession() { - return new StatelessSessionImpl( (SessionFactoryImpl) sessionFactory, this ); + return new StatelessSessionImpl( SessionFactoryImpl.this, this ); } }; } diff --git a/hibernate-core/src/main/java/org/hibernate/internal/SessionImpl.java b/hibernate-core/src/main/java/org/hibernate/internal/SessionImpl.java index f81f33320029..171fde9b9163 100644 --- a/hibernate-core/src/main/java/org/hibernate/internal/SessionImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/internal/SessionImpl.java @@ -1984,7 +1984,7 @@ public int getFetchBatchSize() { return loadQueryInfluencers.getBatchSize(); } - @Override + @Override @Deprecated(forRemoval = true) public LobHelper getLobHelper() { return Hibernate.getLobHelper(); } diff --git a/hibernate-core/src/main/java/org/hibernate/internal/StatelessSessionImpl.java b/hibernate-core/src/main/java/org/hibernate/internal/StatelessSessionImpl.java index 2cf5fcf7307b..100168c55926 100644 --- a/hibernate-core/src/main/java/org/hibernate/internal/StatelessSessionImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/internal/StatelessSessionImpl.java @@ -20,6 +20,7 @@ import org.hibernate.collection.spi.CollectionSemantics; import org.hibernate.collection.spi.PersistentCollection; import org.hibernate.engine.creation.internal.SessionCreationOptions; +import org.hibernate.engine.creation.internal.SharedSessionCreationOptions; import org.hibernate.engine.internal.TransactionCompletionCallbacksImpl; import org.hibernate.engine.spi.EntityKey; import org.hibernate.engine.spi.LoadQueryInfluencers; @@ -27,6 +28,7 @@ import org.hibernate.engine.spi.SessionImplementor; import org.hibernate.engine.spi.StatelessSessionImplementor; import org.hibernate.engine.spi.TransactionCompletionCallbacks; +import org.hibernate.engine.spi.TransactionCompletionCallbacksImplementor; import org.hibernate.engine.transaction.jta.platform.spi.JtaPlatform; import org.hibernate.event.monitor.spi.DiagnosticEvent; import org.hibernate.event.service.spi.EventListenerGroups; @@ -117,14 +119,18 @@ public class StatelessSessionImpl extends AbstractSharedSessionContract implemen private final LoadQueryInfluencers influencers; private final PersistenceContext temporaryPersistenceContext; private final boolean connectionProvided; - private final TransactionCompletionCallbacksImpl transactionCompletionCallbacks; + private final TransactionCompletionCallbacksImplementor transactionCompletionCallbacks; private final EventListenerGroups eventListenerGroups; public StatelessSessionImpl(SessionFactoryImpl factory, SessionCreationOptions options) { super( factory, options ); connectionProvided = options.getConnection() != null; - transactionCompletionCallbacks = new TransactionCompletionCallbacksImpl( this ); + transactionCompletionCallbacks = + options instanceof SharedSessionCreationOptions sharedOptions + && sharedOptions.isTransactionCoordinatorShared() + ? sharedOptions.getTransactionCompletionCallbacks() + : new TransactionCompletionCallbacksImpl( this ); temporaryPersistenceContext = createPersistenceContext( this ); influencers = new LoadQueryInfluencers( getFactory() ); eventListenerGroups = factory.getEventListenerGroups(); @@ -1428,6 +1434,11 @@ public Object loadFromSecondLevelCache(EntityPersister persister, EntityKey enti return CacheLoadHelper.loadFromSecondLevelCache( this, instanceToLoad, lockMode, persister, entityKey ); } + @Override + public TransactionCompletionCallbacksImplementor getTransactionCompletionCallbacksImplementor() { + return transactionCompletionCallbacks.forSharing(); + } + @Override public T unwrap(Class type) { checkOpen(); diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/interceptor/InterceptorTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/interceptor/InterceptorTest.java index d12c007c25b9..a22d1dc0f152 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/interceptor/InterceptorTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/interceptor/InterceptorTest.java @@ -41,11 +41,6 @@ public String[] getMappings() { return new String[] { "interceptor/User.hbm.xml", "interceptor/Image.hbm.xml" }; } - @Override - protected String getBaseForMappings() { - return "org/hibernate/orm/test/"; - } - @Test public void testCollectionIntercept() { Session s = openSession( new CollectionInterceptor() ); diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/interceptor/StatefulInterceptor.java b/hibernate-core/src/test/java/org/hibernate/orm/test/interceptor/StatefulInterceptor.java index 905017398fe6..59265f284aae 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/interceptor/StatefulInterceptor.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/interceptor/StatefulInterceptor.java @@ -16,7 +16,7 @@ public class StatefulInterceptor implements Interceptor { private Session session; - private List list = new ArrayList(); + private final List list = new ArrayList<>(); @Override public boolean onPersist(Object entity, Object id, Object[] state, String[] propertyNames, Type[] types) { @@ -35,10 +35,10 @@ public boolean onFlushDirty(Object entity, Object id, Object[] currentState, Obj } @Override - public void postFlush(Iterator entities) { - if ( list.size()>0 ) { - for ( Iterator iter = list.iterator(); iter.hasNext(); ) { - session.persist( iter.next() ); + public void postFlush(Iterator entities) { + if ( !list.isEmpty() ) { + for ( Object object : list ) { + session.persist( object ); } list.clear(); session.flush(); @@ -48,5 +48,4 @@ public void postFlush(Iterator entities) { public void setSession(Session s) { session = s; } - } diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/sharedSession/DummyInterceptor.java b/hibernate-core/src/test/java/org/hibernate/orm/test/sharedSession/DummyInterceptor.java new file mode 100644 index 000000000000..e0d9db279dea --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/sharedSession/DummyInterceptor.java @@ -0,0 +1,10 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * Copyright Red Hat Inc. and Hibernate Authors + */ +package org.hibernate.orm.test.sharedSession; + +import org.hibernate.Interceptor; + +public class DummyInterceptor implements Interceptor { +} diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/sharedSession/SimpleSharedSessionBuildingTests.java b/hibernate-core/src/test/java/org/hibernate/orm/test/sharedSession/SimpleSharedSessionBuildingTests.java new file mode 100644 index 000000000000..0e8977014739 --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/sharedSession/SimpleSharedSessionBuildingTests.java @@ -0,0 +1,178 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * Copyright Red Hat Inc. and Hibernate Authors + */ +package org.hibernate.orm.test.sharedSession; + +import jakarta.persistence.Entity; +import jakarta.persistence.Id; +import jakarta.persistence.Table; +import org.hibernate.Interceptor; +import org.hibernate.engine.spi.SessionImplementor; +import org.hibernate.engine.spi.StatelessSessionImplementor; +import org.hibernate.resource.jdbc.spi.StatementInspector; +import org.hibernate.testing.orm.junit.DomainModel; +import org.hibernate.testing.orm.junit.SessionFactory; +import org.hibernate.testing.orm.junit.SessionFactoryScope; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.Test; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.assertSame; + +/** + * @author Steve Ebersole + */ +@SuppressWarnings("JUnitMalformedDeclaration") +@DomainModel(annotatedClasses = SimpleSharedSessionBuildingTests.Something.class) +@SessionFactory(useCollectingStatementInspector = true, interceptorClass = DummyInterceptor.class) +public class SimpleSharedSessionBuildingTests { + + @Test + void testStatementInspector(SessionFactoryScope factoryScope) { + final var sqlCollector = factoryScope.getCollectingStatementInspector(); + + // apply a special StatementInspector to the base and check the behavior of the various options + final var appliedToBase = new StatementInspectorImpl( "Applied to base" ); + + try (var base = factoryScope.getSessionFactory() + .withOptions() + .statementInspector( appliedToBase ) + .openSession()) { + + // baseline: + try (var nested = (SessionImplementor) base. + sessionWithOptions() + .openSession()) { + assertThat( nested.getJdbcSessionContext().getStatementInspector() ).isSameAs( sqlCollector ); + } + + // 1. noStatementInspector + try (var nested = (SessionImplementor) base + .sessionWithOptions() + .noStatementInspector() + .openSession()) { + assertThat( nested.getJdbcSessionContext().getStatementInspector() ).isNotSameAs( sqlCollector ); + assertThat( nested.getJdbcSessionContext().getStatementInspector() ).isNotSameAs( appliedToBase ); + } + + // 2. statementInspector() + try (var nested = (SessionImplementor) base + .sessionWithOptions() + .statementInspector() + .openSession()) { + assertThat( nested.getJdbcSessionContext().getStatementInspector() ).isSameAs( appliedToBase ); + } + } + } + + @Test + void testInterceptor(SessionFactoryScope factoryScope) { + final var sfInterceptor = factoryScope.getSessionFactory().getSessionFactoryOptions().getInterceptor(); + + // apply a special StatementInspector to the base and check the behavior of the various options + final var appliedToBase = new InterceptorImpl( "Applied to base" ); + + try (var base = factoryScope.getSessionFactory() + .withOptions() + .interceptor( appliedToBase ) + .openSession()) { + + // baseline - should use the Interceptor from SF + try (var nested = (SessionImplementor) base. + sessionWithOptions() + .openSession()) { + assertThat( nested.getInterceptor() ).isSameAs( sfInterceptor ); + } + + // 1. noInterceptor() - should use no (Empty)Interceptor + try (var nested = (SessionImplementor) base + .sessionWithOptions() + .noInterceptor() + .openSession()) { + assertThat( nested.getInterceptor() ).isNotSameAs( sfInterceptor ); + assertThat( nested.getInterceptor() ).isNotSameAs( appliedToBase ); + } + + // 2. interceptor() - should share the interceptor from the base session + try (var nested = (SessionImplementor) base + .sessionWithOptions() + .interceptor() + .openSession()) { + assertThat( nested.getInterceptor() ).isSameAs( appliedToBase ); + } + } + } + + @Test + void testUsage(SessionFactoryScope factoryScope) { + final var sqlCollector = factoryScope.getCollectingStatementInspector(); + + // try from Session + sqlCollector.clear(); + factoryScope.inTransaction( (statefulSession) -> { + try (var session = statefulSession + .sessionWithOptions() + .connection() + .openSession()) { + session.persist( new Something( 1, "first" ) ); + assertSame( statefulSession.getTransaction(), session.getTransaction() ); + assertSame( statefulSession.getJdbcCoordinator(), + ((SessionImplementor) session).getJdbcCoordinator() ); + assertSame( statefulSession.getTransactionCompletionCallbacksImplementor(), + ((SessionImplementor) session).getTransactionCompletionCallbacksImplementor() ); + session.flush(); //TODO: should not be needed! + } + } ); + assertThat( sqlCollector.getSqlQueries() ).hasSize( 1 ); + + // try from StatelessSession + sqlCollector.clear(); + factoryScope.inStatelessTransaction( (statelessSession) -> { + try (var statefulSession = statelessSession + .sessionWithOptions() + .connection() + .openSession()) { + statefulSession.persist( new Something( 2, "first" ) ); + assertSame( statefulSession.getTransaction(), statelessSession.getTransaction() ); + assertSame( ((SessionImplementor) statefulSession).getJdbcCoordinator(), + ((StatelessSessionImplementor) statelessSession).getJdbcCoordinator() ); + assertSame( ((SessionImplementor) statefulSession).getTransactionCompletionCallbacksImplementor(), + ((StatelessSessionImplementor) statelessSession).getTransactionCompletionCallbacksImplementor() ); + statefulSession.flush(); //TODO: should not be needed! + } + } ); + assertThat( sqlCollector.getSqlQueries() ).hasSize( 1 ); + } + + @AfterEach + void dropTestData(SessionFactoryScope factoryScope) { + factoryScope.dropData(); + } + + @Entity(name="Something") + @Table(name="somethings") + public static class Something { + @Id + private Integer id; + private String name; + + public Something() { + } + + public Something(Integer id, String name) { + this.id = id; + this.name = name; + } + } + + public record StatementInspectorImpl(String name) implements StatementInspector { + @Override + public String inspect(String sql) { + return sql; + } + } + + public record InterceptorImpl(String name) implements Interceptor { + } +} diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/stateless/shared/SimpleSharedStatelessSessionBuildingTests.java b/hibernate-core/src/test/java/org/hibernate/orm/test/stateless/shared/SimpleSharedStatelessSessionBuildingTests.java index 5e7cc35b8939..39764908cb59 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/stateless/shared/SimpleSharedStatelessSessionBuildingTests.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/stateless/shared/SimpleSharedStatelessSessionBuildingTests.java @@ -8,12 +8,9 @@ import jakarta.persistence.Id; import jakarta.persistence.Table; import org.hibernate.Interceptor; -import org.hibernate.Session; -import org.hibernate.StatelessSession; import org.hibernate.engine.spi.StatelessSessionImplementor; import org.hibernate.orm.test.interceptor.StatefulInterceptor; import org.hibernate.resource.jdbc.spi.StatementInspector; -import org.hibernate.testing.jdbc.SQLStatementInspector; import org.hibernate.testing.orm.junit.DomainModel; import org.hibernate.testing.orm.junit.SessionFactory; import org.hibernate.testing.orm.junit.SessionFactoryScope; @@ -21,6 +18,7 @@ import org.junit.jupiter.api.Test; import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.assertSame; /** * @author Steve Ebersole @@ -32,25 +30,25 @@ public class SimpleSharedStatelessSessionBuildingTests { @Test void testStatementInspector(SessionFactoryScope factoryScope) { - final SQLStatementInspector sqlCollector = factoryScope.getCollectingStatementInspector(); + final var sqlCollector = factoryScope.getCollectingStatementInspector(); // apply a special StatementInspector to the base and check the behavior of the various options - final StatementInspectorImpl appliedToBase = new StatementInspectorImpl( "Applied to base" ); + final var appliedToBase = new StatementInspectorImpl( "Applied to base" ); - try (Session base = factoryScope.getSessionFactory() + try (var base = factoryScope.getSessionFactory() .withOptions() .statementInspector( appliedToBase ) .openSession()) { // baseline: - try (StatelessSessionImplementor nested = (StatelessSessionImplementor) base. + try (var nested = (StatelessSessionImplementor) base. statelessWithOptions() .open()) { assertThat( nested.getJdbcSessionContext().getStatementInspector() ).isSameAs( sqlCollector ); } // 1. noStatementInspector - try (StatelessSessionImplementor nested = (StatelessSessionImplementor) base + try (var nested = (StatelessSessionImplementor) base .statelessWithOptions() .noStatementInspector() .open()) { @@ -59,7 +57,7 @@ void testStatementInspector(SessionFactoryScope factoryScope) { } // 2. statementInspector() - try (StatelessSessionImplementor nested = (StatelessSessionImplementor) base + try (var nested = (StatelessSessionImplementor) base .statelessWithOptions() .statementInspector() .open()) { @@ -70,25 +68,25 @@ void testStatementInspector(SessionFactoryScope factoryScope) { @Test void testInterceptor(SessionFactoryScope factoryScope) { - final Interceptor sfInterceptor = factoryScope.getSessionFactory().getSessionFactoryOptions().getInterceptor(); + final var sfInterceptor = factoryScope.getSessionFactory().getSessionFactoryOptions().getInterceptor(); // apply a special StatementInspector to the base and check the behavior of the various options - final InterceptorImpl appliedToBase = new InterceptorImpl( "Applied to base" ); + final var appliedToBase = new InterceptorImpl( "Applied to base" ); - try (Session base = factoryScope.getSessionFactory() + try (var base = factoryScope.getSessionFactory() .withOptions() .interceptor( appliedToBase ) .openSession()) { // baseline - should use the Interceptor from SF - try (StatelessSessionImplementor nested = (StatelessSessionImplementor) base. + try (var nested = (StatelessSessionImplementor) base. statelessWithOptions() .open()) { assertThat( nested.getInterceptor() ).isSameAs( sfInterceptor ); } // 1. noInterceptor() - should use no (Empty)Interceptor - try (StatelessSessionImplementor nested = (StatelessSessionImplementor) base + try (var nested = (StatelessSessionImplementor) base .statelessWithOptions() .noInterceptor() .open()) { @@ -97,7 +95,7 @@ void testInterceptor(SessionFactoryScope factoryScope) { } // 2. interceptor() - should share the interceptor from the base session - try (StatelessSessionImplementor nested = (StatelessSessionImplementor) base + try (var nested = (StatelessSessionImplementor) base .statelessWithOptions() .interceptor() .open()) { @@ -108,30 +106,40 @@ void testInterceptor(SessionFactoryScope factoryScope) { @Test void testUsage(SessionFactoryScope factoryScope) { - final SQLStatementInspector sqlCollector = factoryScope.getCollectingStatementInspector(); + final var sqlCollector = factoryScope.getCollectingStatementInspector(); // try from Session sqlCollector.clear(); factoryScope.inTransaction( (statefulSession) -> { - try (StatelessSession statelessSession = statefulSession + try (var statelessSession = statefulSession .statelessWithOptions() .connection() .open()) { statelessSession.insert( new Something( 1, "first" ) ); + assertSame( statefulSession.getTransaction(), statelessSession.getTransaction() ); + assertSame( statefulSession.getJdbcCoordinator(), + ((StatelessSessionImplementor) statelessSession).getJdbcCoordinator() ); + assertSame( statefulSession.getTransactionCompletionCallbacksImplementor(), + ((StatelessSessionImplementor) statelessSession).getTransactionCompletionCallbacksImplementor() ); } } ); + assertThat( sqlCollector.getSqlQueries() ).hasSize( 1 ); // try from StatelessSession sqlCollector.clear(); factoryScope.inStatelessTransaction( (statelessSession) -> { - try (StatelessSession ss2 = statelessSession + try (var session = statelessSession .statelessWithOptions() .connection() .open()) { - ss2.insert( new Something( 2, "first" ) ); + session.insert( new Something( 2, "first" ) ); + assertSame( session.getTransaction(), statelessSession.getTransaction() ); + assertSame( ((StatelessSessionImplementor) session).getJdbcCoordinator(), + ((StatelessSessionImplementor) statelessSession).getJdbcCoordinator() ); + assertSame( ((StatelessSessionImplementor) session).getTransactionCompletionCallbacksImplementor(), + ((StatelessSessionImplementor) statelessSession).getTransactionCompletionCallbacksImplementor() ); } } ); - assertThat( sqlCollector.getSqlQueries() ).hasSize( 1 ); }