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

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

commit 2b4b3b4edcbb4f2fef1751e95f5d70258c81cc09
Author: Walter Duque de Estrada <[email protected]>
AuthorDate: Thu Mar 5 17:57:21 2026 -0600

    hibernate7: spec for GrailsSessionContext and InstanceApiHelper
---
 .../grails/orm/hibernate/GrailsSessionContext.java |   9 +-
 .../support/HibernateDatastoreFactoryBean.groovy   |  62 -------
 .../HibernateDialectDetectorFactoryBean.java       | 204 ---------------------
 .../sessioncontext/GrailsSessionContextSpec.groovy | 126 +++++++++++--
 .../orm/hibernate/InstanceApiHelperSpec.groovy     |  71 +++++++
 5 files changed, 183 insertions(+), 289 deletions(-)

diff --git 
a/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/GrailsSessionContext.java
 
b/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/GrailsSessionContext.java
index 96bedd079e..e72a03ea45 100644
--- 
a/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/GrailsSessionContext.java
+++ 
b/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/GrailsSessionContext.java
@@ -70,7 +70,7 @@ public class GrailsSessionContext implements 
CurrentSessionContext {
 
   public void initJta() {
     JtaPlatform jtaPlatform = 
sessionFactory.getServiceRegistry().getService(JtaPlatform.class);
-    TransactionManager transactionManager = 
jtaPlatform.retrieveTransactionManager();
+    TransactionManager transactionManager = jtaPlatform != null ? 
jtaPlatform.retrieveTransactionManager() : null;
     jtaSessionContext =
         transactionManager == null ? null : new 
SpringJtaSessionContext(sessionFactory);
   }
@@ -82,9 +82,8 @@ public class GrailsSessionContext implements 
CurrentSessionContext {
       return (Session) value;
     }
 
-    if (value instanceof SessionHolder) {
-      SessionHolder sessionHolder = (SessionHolder) value;
-      Session session = sessionHolder.getSession();
+    if (value instanceof SessionHolder sessionHolder) {
+        Session session = sessionHolder.getSession();
       if (TransactionSynchronizationManager.isSynchronizationActive()
           && !sessionHolder.isSynchronizedWithTransaction()) {
         TransactionSynchronizationManager.registerSynchronization(
@@ -221,7 +220,7 @@ public class GrailsSessionContext implements 
CurrentSessionContext {
 
     ServiceBinding<JtaPlatform> sb =
         
sessionFactoryImpl.getServiceRegistry().locateServiceBinding(JtaPlatform.class);
-    if (sb == null) {
+    if (sb == null || sb.getService() == null) {
       return null;
     }
 
diff --git 
a/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/support/HibernateDatastoreFactoryBean.groovy
 
b/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/support/HibernateDatastoreFactoryBean.groovy
deleted file mode 100644
index 2c981dd653..0000000000
--- 
a/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/support/HibernateDatastoreFactoryBean.groovy
+++ /dev/null
@@ -1,62 +0,0 @@
-package org.grails.orm.hibernate.support
-
-import groovy.transform.CompileStatic
-import org.grails.datastore.mapping.model.MappingContext
-import org.grails.orm.hibernate.HibernateDatastore
-import org.hibernate.SessionFactory
-import org.springframework.beans.BeansException
-import org.springframework.beans.factory.FactoryBean
-import org.springframework.context.ApplicationContext
-import org.springframework.context.ApplicationContextAware
-import org.springframework.core.env.PropertyResolver
-/**
- * Helper for constructing the datastore
- *
- * @author Graeme Rocher
- * @since 5.0
- */
-@CompileStatic
-public class HibernateDatastoreFactoryBean<T extends HibernateDatastore> 
implements FactoryBean<T>, ApplicationContextAware {
-
-    private final Class<T> objectType;
-    private final MappingContext mappingContext;
-    private final SessionFactory sessionFactory;
-    private final PropertyResolver configuration;
-    private final String dataSourceName;
-    ApplicationContext applicationContext;
-
-    HibernateDatastoreFactoryBean(Class<T> objectType, MappingContext 
mappingContext, SessionFactory sessionFactory, PropertyResolver configuration, 
String dataSourceName) {
-        this.objectType = objectType
-        this.mappingContext = mappingContext
-        this.sessionFactory = sessionFactory
-        this.configuration = configuration
-        this.dataSourceName = dataSourceName
-    }
-
-    @Override
-    public void setApplicationContext(ApplicationContext applicationContext) 
throws BeansException {
-        this.applicationContext = applicationContext;
-    }
-
-    @Override
-    public T getObject() throws Exception {
-        HibernateDatastore datastore = objectType.newInstance(mappingContext, 
sessionFactory, configuration, dataSourceName)
-
-
-        if(applicationContext != null) {
-            datastore.setApplicationContext(applicationContext)
-        }
-
-        return datastore;
-    }
-
-    @Override
-    public Class<?> getObjectType() {
-        return objectType;
-    }
-
-    @Override
-    public boolean isSingleton() {
-        return true;
-    }
-}
diff --git 
a/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/support/HibernateDialectDetectorFactoryBean.java
 
b/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/support/HibernateDialectDetectorFactoryBean.java
deleted file mode 100644
index 4ca7317583..0000000000
--- 
a/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/support/HibernateDialectDetectorFactoryBean.java
+++ /dev/null
@@ -1,204 +0,0 @@
-/*
- *  Licensed to the Apache Software Foundation (ASF) under one
- *  or more contributor license agreements.  See the NOTICE file
- *  distributed with this work for additional information
- *  regarding copyright ownership.  The ASF licenses this file
- *  to you under the Apache License, Version 2.0 (the
- *  "License"); you may not use this file except in compliance
- *  with the License.  You may obtain a copy of the License at
- *
- *    https://www.apache.org/licenses/LICENSE-2.0
- *
- *  Unless required by applicable law or agreed to in writing,
- *  software distributed under the License is distributed on an
- *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- *  KIND, either express or implied.  See the License for the
- *  specific language governing permissions and limitations
- *  under the License.
- */
-package org.grails.orm.hibernate.support;
-
-import java.sql.Connection;
-import java.sql.SQLException;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.Properties;
-import java.util.stream.Collectors;
-import javax.sql.DataSource;
-import org.checkerframework.checker.initialization.qual.Initialized;
-import org.checkerframework.checker.nullness.qual.NonNull;
-import org.checkerframework.checker.nullness.qual.Nullable;
-import org.checkerframework.checker.nullness.qual.UnknownKeyFor;
-import 
org.grails.orm.hibernate.exceptions.CouldNotDetermineHibernateDialectException;
-import org.hibernate.HibernateException;
-import 
org.hibernate.boot.registry.classloading.internal.ClassLoaderServiceImpl;
-import org.hibernate.boot.registry.selector.internal.StrategySelectorImpl;
-import org.hibernate.boot.registry.selector.spi.StrategySelector;
-import org.hibernate.dialect.Dialect;
-import org.hibernate.engine.jdbc.dialect.internal.DialectFactoryImpl;
-import org.hibernate.engine.jdbc.dialect.internal.StandardDialectResolver;
-import org.hibernate.engine.jdbc.dialect.spi.*;
-import org.hibernate.service.Service;
-import org.hibernate.service.ServiceRegistry;
-import org.hibernate.service.spi.ServiceBinding;
-import org.hibernate.service.spi.ServiceRegistryImplementor;
-import org.springframework.beans.factory.FactoryBean;
-import org.springframework.beans.factory.InitializingBean;
-import org.springframework.jdbc.datasource.DataSourceUtils;
-import org.springframework.jdbc.support.JdbcUtils;
-import org.springframework.jdbc.support.MetaDataAccessException;
-import org.springframework.util.Assert;
-import org.springframework.util.StringUtils;
-
-/**
- * @author Steven Devijver
- * @author Graeme Rocher
- * @author Burt Beckwith
- */
-@SuppressWarnings({"PMD.CloseResource", "PMD.DataflowAnomalyAnalysis"})
-public class HibernateDialectDetectorFactoryBean implements 
FactoryBean<String>, InitializingBean {
-
-  private DataSource dataSource;
-  private Properties vendorNameDialectMappings;
-  private String hibernateDialectClassName;
-  private Dialect hibernateDialect;
-  private Properties hibernateProperties = new Properties();
-
-  public void setHibernateProperties(Properties hibernateProperties) {
-    this.hibernateProperties = hibernateProperties;
-  }
-
-  public void setDataSource(DataSource dataSource) {
-    this.dataSource = dataSource;
-  }
-
-  public void setVendorNameDialectMappings(Properties mappings) {
-    vendorNameDialectMappings = mappings;
-  }
-
-  public String getObject() {
-    return hibernateDialectClassName;
-  }
-
-  public Class<String> getObjectType() {
-    return String.class;
-  }
-
-  public boolean isSingleton() {
-    return true;
-  }
-
-  public void afterPropertiesSet() throws MetaDataAccessException {
-    Assert.notNull(dataSource, "Data source is not set!");
-    Assert.notNull(vendorNameDialectMappings, "Vendor name/dialect mappings 
are not set!");
-
-    Connection connection = null;
-
-    String dbName =
-        (String) JdbcUtils.extractDatabaseMetaData(dataSource, 
"getDatabaseProductName");
-
-    try {
-      connection = DataSourceUtils.getConnection(dataSource);
-
-      try {
-        final DialectFactory dialectFactory = createDialectFactory();
-        final Connection finalConnection = connection;
-        DialectResolutionInfoSource infoSource =
-            new DialectResolutionInfoSource() {
-              @Override
-              public DialectResolutionInfo getDialectResolutionInfo() {
-                try {
-                  return new DatabaseMetaDataDialectResolutionInfoAdapter(
-                      finalConnection.getMetaData());
-                } catch (SQLException e) {
-                  throw new CouldNotDetermineHibernateDialectException(
-                      "Could not determine Hibernate dialect", e);
-                }
-              }
-            };
-        HashMap<String, Object> collect =
-            hibernateProperties.entrySet().stream()
-                .collect(
-                    Collectors.toMap(
-                        e -> String.valueOf(e.getKey()),
-                        Map.Entry::getValue,
-                        (prev, next) -> next,
-                        HashMap::new));
-        hibernateDialect = dialectFactory.buildDialect(collect, infoSource);
-        hibernateDialectClassName = hibernateDialect.getClass().getName();
-      } catch (HibernateException e) {
-        hibernateDialectClassName = 
vendorNameDialectMappings.getProperty(dbName);
-      }
-
-      if (!StringUtils.hasText(hibernateDialectClassName)) {
-        throw new CouldNotDetermineHibernateDialectException(
-            "Could not determine Hibernate dialect for database name [" + 
dbName + "]!");
-      }
-    } finally {
-      DataSourceUtils.releaseConnection(connection, dataSource);
-    }
-  }
-
-  // should be using the ServiceRegistry, but getting it from the 
SessionFactory at startup fails in
-  // Spring
-  protected DialectFactory createDialectFactory() {
-    DialectFactoryImpl factory = new DialectFactoryImpl();
-    factory.injectServices(
-        new ServiceRegistryImplementor() {
-
-          @Override
-          public <R extends Service> R getService(Class<R> serviceRole) {
-            if (serviceRole == DialectResolver.class) {
-              return (R) new StandardDialectResolver();
-            } else if (serviceRole == StrategySelector.class) {
-              return (R)
-                  new StrategySelectorImpl(
-                      new 
ClassLoaderServiceImpl(Thread.currentThread().getContextClassLoader()));
-            }
-            return null;
-          }
-
-          @Override
-          public <R extends Service> R requireService(
-              @UnknownKeyFor @NonNull @Initialized Class<R> serviceRole) {
-            return 
ServiceRegistryImplementor.super.requireService(serviceRole);
-          }
-
-          @Override
-          public <R extends Service> ServiceBinding<R> 
locateServiceBinding(Class<R> serviceRole) {
-            return null;
-          }
-
-          @Override
-          public void close() {
-            ServiceRegistryImplementor.super.close();
-          }
-
-          @Override
-          public void destroy() {}
-
-          @Override
-          public void registerChild(ServiceRegistryImplementor child) {}
-
-          @Override
-          public void deRegisterChild(ServiceRegistryImplementor child) {}
-
-          @Override
-          public <T extends Service> @Nullable T fromRegistryOrChildren(
-              @UnknownKeyFor @NonNull @Initialized Class<T> serviceRole) {
-            return null;
-          }
-
-          @Override
-          public ServiceRegistry getParentServiceRegistry() {
-            return null;
-          }
-
-          @Override
-          public boolean isActive() {
-            return true;
-          }
-        });
-    return factory;
-  }
-}
diff --git 
a/grails-data-hibernate7/core/src/test/groovy/grails/gorm/specs/sessioncontext/GrailsSessionContextSpec.groovy
 
b/grails-data-hibernate7/core/src/test/groovy/grails/gorm/specs/sessioncontext/GrailsSessionContextSpec.groovy
index d9d1461d48..4534c4f506 100644
--- 
a/grails-data-hibernate7/core/src/test/groovy/grails/gorm/specs/sessioncontext/GrailsSessionContextSpec.groovy
+++ 
b/grails-data-hibernate7/core/src/test/groovy/grails/gorm/specs/sessioncontext/GrailsSessionContextSpec.groovy
@@ -1,3 +1,21 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    https://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
 package grails.gorm.specs.sessioncontext
 
 import grails.gorm.specs.HibernateGormDatastoreSpec
@@ -11,6 +29,20 @@ import 
org.springframework.transaction.support.TransactionSynchronizationManager
 
 class GrailsSessionContextSpec extends HibernateGormDatastoreSpec {
 
+    def setup() {
+        
TransactionSynchronizationManager.unbindResourceIfPossible(manager.hibernateDatastore.sessionFactory)
+        if (TransactionSynchronizationManager.isSynchronizationActive()) {
+            TransactionSynchronizationManager.clearSynchronization()
+        }
+    }
+
+    def cleanup() {
+        
TransactionSynchronizationManager.unbindResourceIfPossible(manager.hibernateDatastore.sessionFactory)
+        if (TransactionSynchronizationManager.isSynchronizationActive()) {
+            TransactionSynchronizationManager.clearSynchronization()
+        }
+    }
+
     void "test GrailsSessionContext can be created with a SessionFactory"() {
         given:
         HibernateDatastore hibernateDatastore = manager.hibernateDatastore
@@ -25,12 +57,9 @@ class GrailsSessionContextSpec extends 
HibernateGormDatastoreSpec {
 
     void "test currentSession() returns session bound via 
TransactionSynchronizationManager"() {
         given:
-        HibernateDatastore hibernateDatastore = manager.hibernateDatastore
-        SessionFactoryImplementor sessionFactory = 
hibernateDatastore.sessionFactory as SessionFactoryImplementor
+        SessionFactoryImplementor sessionFactory = 
manager.hibernateDatastore.sessionFactory as SessionFactoryImplementor
         GrailsSessionContext sessionContext = new 
GrailsSessionContext(sessionFactory)
         Session session = sessionFactory.openSession()
-        // unbind whatever the test framework bound, then bind our own session
-        
TransactionSynchronizationManager.unbindResourceIfPossible(sessionFactory)
         TransactionSynchronizationManager.bindResource(sessionFactory, new 
SessionHolder(session))
 
         when:
@@ -41,36 +70,26 @@ class GrailsSessionContextSpec extends 
HibernateGormDatastoreSpec {
         current == session
 
         cleanup:
-        
TransactionSynchronizationManager.unbindResourceIfPossible(sessionFactory)
         if (session.isOpen()) session.close()
     }
 
     void "test currentSession() throws when no session is bound and 
allowCreate is false"() {
         given:
-        HibernateDatastore hibernateDatastore = manager.hibernateDatastore
-        SessionFactoryImplementor sessionFactory = 
hibernateDatastore.sessionFactory as SessionFactoryImplementor
+        SessionFactoryImplementor sessionFactory = 
manager.hibernateDatastore.sessionFactory as SessionFactoryImplementor
         GrailsSessionContext sessionContext = new 
GrailsSessionContext(sessionFactory)
-        // unbind whatever the test framework bound
-        def saved = 
TransactionSynchronizationManager.unbindResourceIfPossible(sessionFactory)
 
         when:
         sessionContext.currentSession()
 
         then:
         thrown(org.hibernate.HibernateException)
-
-        cleanup:
-        // restore the original binding so the framework is not broken for 
subsequent tests
-        if (saved) 
TransactionSynchronizationManager.bindResource(sessionFactory, saved)
     }
 
     void "test currentSession() returns session when bound as plain Session 
resource"() {
         given:
-        HibernateDatastore hibernateDatastore = manager.hibernateDatastore
-        SessionFactoryImplementor sessionFactory = 
hibernateDatastore.sessionFactory as SessionFactoryImplementor
+        SessionFactoryImplementor sessionFactory = 
manager.hibernateDatastore.sessionFactory as SessionFactoryImplementor
         GrailsSessionContext sessionContext = new 
GrailsSessionContext(sessionFactory)
         Session session = sessionFactory.openSession()
-        
TransactionSynchronizationManager.unbindResourceIfPossible(sessionFactory)
         TransactionSynchronizationManager.bindResource(sessionFactory, session)
 
         when:
@@ -80,8 +99,79 @@ class GrailsSessionContextSpec extends 
HibernateGormDatastoreSpec {
         current == session
 
         cleanup:
-        
TransactionSynchronizationManager.unbindResourceIfPossible(sessionFactory)
         if (session.isOpen()) session.close()
     }
-}
 
+    void "test initJta handles missing JtaPlatform"() {
+        given:
+        SessionFactoryImplementor sessionFactory = 
Mock(SessionFactoryImplementor)
+        org.hibernate.service.spi.ServiceRegistryImplementor registry = 
Mock(org.hibernate.service.spi.ServiceRegistryImplementor)
+        sessionFactory.getServiceRegistry() >> registry
+        
registry.getService(org.hibernate.engine.transaction.jta.platform.spi.JtaPlatform)
 >> null
+        GrailsSessionContext sessionContext = new 
GrailsSessionContext(sessionFactory)
+
+        when:
+        sessionContext.initJta()
+
+        then:
+        noExceptionThrown()
+        sessionContext.jtaSessionContext == null
+    }
+
+    void "test currentSession() switches to AUTO flush mode when sync is 
active"() {
+        given:
+        SessionFactoryImplementor sessionFactory = 
manager.hibernateDatastore.sessionFactory as SessionFactoryImplementor
+        GrailsSessionContext sessionContext = new 
GrailsSessionContext(sessionFactory)
+        Session session = sessionFactory.openSession()
+        session.setHibernateFlushMode(FlushMode.MANUAL)
+        
+        TransactionSynchronizationManager.initSynchronization()
+        TransactionSynchronizationManager.bindResource(sessionFactory, new 
SessionHolder(session))
+
+        when:
+        Session current = sessionContext.currentSession()
+
+        then:
+        current.getHibernateFlushMode() == FlushMode.AUTO
+        
+        cleanup:
+        if (session.isOpen()) session.close()
+    }
+
+    void "test currentSession() creates a new session when allowCreate is 
true"() {
+        given:
+        SessionFactoryImplementor sessionFactory = 
manager.hibernateDatastore.sessionFactory as SessionFactoryImplementor
+        GrailsSessionContext sessionContext = new 
GrailsSessionContext(sessionFactory)
+        sessionContext.allowCreate = true
+
+        when:
+        Session session = sessionContext.currentSession()
+
+        then:
+        session != null
+        session.isOpen()
+
+        cleanup:
+        if (session?.isOpen()) session.close()
+    }
+
+    void "test currentSession() with active transaction and allowCreate"() {
+        given:
+        SessionFactoryImplementor sessionFactory = 
manager.hibernateDatastore.sessionFactory as SessionFactoryImplementor
+        GrailsSessionContext sessionContext = new 
GrailsSessionContext(sessionFactory)
+        sessionContext.allowCreate = true
+        
+        TransactionSynchronizationManager.initSynchronization()
+
+        when:
+        Session session = sessionContext.currentSession()
+
+        then:
+        session != null
+        TransactionSynchronizationManager.hasResource(sessionFactory)
+        
((SessionHolder)TransactionSynchronizationManager.getResource(sessionFactory)).isSynchronizedWithTransaction()
+
+        cleanup:
+        if (session?.isOpen()) session.close()
+    }
+}
diff --git 
a/grails-data-hibernate7/core/src/test/groovy/org/grails/orm/hibernate/InstanceApiHelperSpec.groovy
 
b/grails-data-hibernate7/core/src/test/groovy/org/grails/orm/hibernate/InstanceApiHelperSpec.groovy
new file mode 100644
index 0000000000..009e04cd0d
--- /dev/null
+++ 
b/grails-data-hibernate7/core/src/test/groovy/org/grails/orm/hibernate/InstanceApiHelperSpec.groovy
@@ -0,0 +1,71 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    https://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+package org.grails.orm.hibernate
+
+import org.hibernate.FlushMode
+import org.hibernate.Session
+import spock.lang.Specification
+
+class InstanceApiHelperSpec extends Specification {
+
+    GrailsHibernateTemplate template = Mock(GrailsHibernateTemplate)
+    Session session = Mock(Session)
+    InstanceApiHelper helper = new InstanceApiHelper(template)
+
+    def "test remove without flush"() {
+        given:
+        def obj = new Object()
+
+        when:
+        helper.remove(obj, false)
+
+        then:
+        1 * template.execute(_) >> { args -> 
+            args[0].doInHibernate(session)
+        }
+        1 * session.remove(obj)
+        0 * session.flush()
+    }
+
+    def "test remove with flush"() {
+        given:
+        def obj = new Object()
+
+        when:
+        helper.remove(obj, true)
+
+        then:
+        1 * template.execute(_) >> { args -> 
+            args[0].doInHibernate(session)
+        }
+        1 * session.remove(obj)
+        1 * session.flush()
+    }
+
+    def "test setFlushModeManual"() {
+        when:
+        helper.setFlushModeManual()
+
+        then:
+        1 * template.execute(_) >> { args -> 
+            args[0].doInHibernate(session)
+        }
+        1 * session.setHibernateFlushMode(FlushMode.MANUAL)
+    }
+}

Reply via email to