You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@grails.apache.org by bo...@apache.org on 2026/05/02 15:35:42 UTC

(grails-core) 13/14: fix(h7): fix withNewSession to open native Hibernate session before binding

This is an automated email from the ASF dual-hosted git repository.

borinquenkid pushed a commit to branch 8.0.x-hibernate7_gorm_enhance
in repository https://gitbox.apache.org/repos/asf/grails-core.git

commit a4b6a26c05ec2d80adf0e2a3092be7784e1fd647
Author: Walter Duque de Estrada <wb...@mac.com>
AuthorDate: Sat May 2 06:04:35 2026 -0500

    fix(h7): fix withNewSession to open native Hibernate session before binding
    
    The previous implementation called sessionFactory.getCurrentSession() inside
    a DatastoreUtils.executeWithNewSession callback to bind the Hibernate session
    under the sessionFactory key. This failed with 'No Session found for current
    thread' because DatastoreUtils.executeWithNewSession only creates a lazy
    HibernateSession wrapper — no real Hibernate session is opened or bound before
    the callback fires.
    
    Fix: open a native Hibernate session via openSession(), bind it to
    TransactionSynchronizationManager under the sessionFactory key, then wrap it
    in a HibernateSession facade for the caller's closure. This matches the same
    contract that HibernateGormStaticApi.withNewSession expects (a HibernateSession
    so it can call getNativeSession()) and that GrailsSessionContext.currentSession()
    requires (a session bound under sessionFactory key).
    
    Fixes: MultiTenancyUnidirectionalOneToManySpec
    
    Co-authored-by: Copilot <22...@users.noreply.github.com>
---
 .../grails/orm/hibernate/HibernateDatastore.java   | 32 +++++++++++++++-------
 1 file changed, 22 insertions(+), 10 deletions(-)

diff --git a/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/HibernateDatastore.java b/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/HibernateDatastore.java
index 9eaeb33d0c..eb1ffde018 100644
--- a/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/HibernateDatastore.java
+++ b/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/HibernateDatastore.java
@@ -996,20 +996,32 @@ public class HibernateDatastore extends AbstractDatastore
     }
 
     public <T> T withNewSession(final Closure<T> callable) {
-        return DatastoreUtils.executeWithNewSession(this, (SessionCallback<T>) session -> {
-            boolean bindHibernate = TransactionSynchronizationManager.getResource(sessionFactory) == null;
+        // Open a fresh native Hibernate session, bind it under the sessionFactory key so
+        // that GrailsSessionContext.currentSession() can find it, then wrap it in the GORM
+        // HibernateSession facade before handing off to the caller's closure.
+        // We cannot use sessionFactory.getCurrentSession() here because no session is bound yet;
+        // and we cannot use DatastoreUtils.executeWithNewSession because it creates only a lazy
+        // HibernateSession wrapper without ever binding a real Hibernate session first.
+        org.hibernate.Session hibSession = openSession();
+        boolean bindHibernate = TransactionSynchronizationManager.getResource(sessionFactory) == null;
+        if (bindHibernate) {
+            TransactionSynchronizationManager.bindResource(sessionFactory,
+                    new org.grails.orm.hibernate.support.hibernate7.SessionHolder(hibSession));
+        }
+        try {
+            HibernateSession gormSession = new HibernateSession(this, sessionFactory);
+            Closure<T> multiTenantCallable = prepareMultiTenantClosure(callable);
+            return multiTenantCallable.call(gormSession);
+        } finally {
             if (bindHibernate) {
-                TransactionSynchronizationManager.bindResource(sessionFactory, new org.grails.orm.hibernate.support.hibernate7.SessionHolder(sessionFactory.getCurrentSession()));
+                TransactionSynchronizationManager.unbindResource(sessionFactory);
             }
             try {
-                Closure<T> multiTenantCallable = prepareMultiTenantClosure(callable);
-                return multiTenantCallable.call(session);
-            } finally {
-                if (bindHibernate) {
-                    TransactionSynchronizationManager.unbindResource(sessionFactory);
-                }
+                hibSession.close();
+            } catch (Exception ignored) {
+                // best-effort close
             }
-        });
+        }
     }
 
     @Override