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 c82b88776ba49c22a7db349b97386e8bef4f206d
Author: Walter Duque de Estrada <[email protected]>
AuthorDate: Thu Mar 19 07:46:40 2026 -0500

    hibernate 7:
    ### Build issue
    **Issue** misconfiguration of grails-data-tck-config.gradle and core 
build.gradle
    
    ### Global Naming Strategy Pollution (Fixed)
    **Issue:** `GrailsDomainBinder` used a static `NamingStrategyProvider`, 
causing naming strategies configured in one test to persist into others.
    **Action:** Refactored `NamingStrategyProvider` into an instance-based 
field. Updated `GrailsDomainBinder`, `HibernateMappingContextConfiguration`, 
and `HibernateConnectionSourceFactory` to pass this instance through the 
configuration lifecycle.
    
    ### Static Mapping Cache (Fixed)
    **Issue:** `MappingCacheHolder` was a static singleton. While 
`HibernateDatastore` attempted to clear it, direct usage of binders in unit 
tests often bypassed this cleanup, leading to stale mappings persisting between 
tests.
    **Action:** Refactored `MappingCacheHolder` to remove the static singleton 
(`getInstance()`). The cache is now instance-based and maintained by 
`HibernateMappingContext`. All consumers (`GrailsDomainBinder`, 
`HibernateDatastore`, `HibernateHqlQuery`, etc.) were updated to use the 
instance tied to their specific configuration cycle, eliminating cross-test 
pollution.
---
 gradle/grails-data-tck-config.gradle               |  8 ++--
 grails-data-hibernate7/core/build.gradle           |  5 +++
 .../grails/orm/hibernate/HibernateDatastore.java   |  2 +-
 .../orm/hibernate/cfg/HibernateMappingContext.java |  5 +++
 .../cfg/HibernateMappingContextConfiguration.java  | 21 +++++++++-
 .../orm/hibernate/cfg/MappingCacheHolder.java      |  8 +---
 .../domainbinding/binder/GrailsDomainBinder.java   | 47 +++++++++++-----------
 .../HibernateConnectionSourceFactory.java          | 10 +++--
 .../orm/hibernate/query/HibernateHqlQuery.java     |  3 +-
 .../orm/hibernate/query/HqlListQueryBuilder.java   |  4 +-
 10 files changed, 71 insertions(+), 42 deletions(-)

diff --git a/gradle/grails-data-tck-config.gradle 
b/gradle/grails-data-tck-config.gradle
index ea0b5ad1a9..ead5c5ef0e 100644
--- a/gradle/grails-data-tck-config.gradle
+++ b/gradle/grails-data-tck-config.gradle
@@ -97,8 +97,8 @@ tasks.withType(Test).configureEach { Test it ->
         }
 
         true
-    }
+        }
 
-    it.testClassesDirs = objects.fileCollection().from(extractTck, 
testClassesDirs)
-    it.finalizedBy(cleanupTask)
-}
+        it.testClassesDirs = project.files(extractTck.map { task -> 
task.outputs.files }, sourceSets.test.output.classesDirs)
+        it.finalizedBy(cleanupTask)
+        }
diff --git a/grails-data-hibernate7/core/build.gradle 
b/grails-data-hibernate7/core/build.gradle
index 10e808337c..188fa62be9 100644
--- a/grails-data-hibernate7/core/build.gradle
+++ b/grails-data-hibernate7/core/build.gradle
@@ -126,6 +126,11 @@ dependencies {
 
 }
 
+sourceSets {
+    test {
+        groovy.srcDirs = ['src/test/groovy']
+    }
+}
 
 apply {
     from 
rootProject.layout.projectDirectory.file('gradle/hibernate7-test-config.gradle')
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 40afaf588f..fc85f25ea0 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
@@ -751,7 +751,7 @@ public class HibernateDatastore extends AbstractDatastore
                     LOG.error("There was an error shutting down GORM for an 
entity: {}", e.getMessage(), e);
                 }
             } finally {
-                MappingCacheHolder.getInstance().clear();
+                getMappingContext().getMappingCacheHolder().clear();
                 try {
                     if (this.gormEnhancer != null) {
                         this.gormEnhancer.close();
diff --git 
a/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/cfg/HibernateMappingContext.java
 
b/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/cfg/HibernateMappingContext.java
index a92e760f28..34d66e095b 100644
--- 
a/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/cfg/HibernateMappingContext.java
+++ 
b/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/cfg/HibernateMappingContext.java
@@ -41,6 +41,11 @@ public class HibernateMappingContext extends 
AbstractMappingContext {
 
     private final HibernateMappingFactory mappingFactory;
     private final MappingConfigurationStrategy syntaxStrategy;
+    private final MappingCacheHolder mappingCacheHolder = new 
MappingCacheHolder();
+
+    public MappingCacheHolder getMappingCacheHolder() {
+        return mappingCacheHolder;
+    }
 
     public HibernateMappingContext(
             HibernateConnectionSourceSettings settings, Object contextObject, 
Class... persistentClasses) {
diff --git 
a/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/cfg/HibernateMappingContextConfiguration.java
 
b/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/cfg/HibernateMappingContextConfiguration.java
index ddeaac06fc..2689df86d7 100644
--- 
a/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/cfg/HibernateMappingContextConfiguration.java
+++ 
b/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/cfg/HibernateMappingContextConfiguration.java
@@ -72,6 +72,7 @@ import org.grails.orm.hibernate.GrailsSessionContext;
 import org.grails.orm.hibernate.HibernateEventListeners;
 import org.grails.orm.hibernate.MetadataIntegrator;
 import org.grails.orm.hibernate.cfg.domainbinding.binder.GrailsDomainBinder;
+import org.grails.orm.hibernate.cfg.domainbinding.util.NamingStrategyProvider;
 
 /**
  * A Configuration that uses a MappingContext to configure Hibernate
@@ -102,6 +103,19 @@ public class HibernateMappingContextConfiguration extends 
Configuration
     private ResourcePatternResolver resourcePatternResolver = new 
PathMatchingResourcePatternResolver();
     //    private MetadataContributor metadataContributor;
     private final Set<Class> additionalClasses = new HashSet<>();
+    private NamingStrategyProvider namingStrategyProvider = new 
NamingStrategyProvider();
+
+    public NamingStrategyProvider getNamingStrategyProvider() {
+        return namingStrategyProvider;
+    }
+
+    public void setNamingStrategyProvider(NamingStrategyProvider 
namingStrategyProvider) {
+        this.namingStrategyProvider = namingStrategyProvider;
+    }
+
+    public MappingCacheHolder getMappingCacheHolder() {
+        return hibernateMappingContext != null ? 
hibernateMappingContext.getMappingCacheHolder() : null;
+    }
 
     public void setHibernateMappingContext(HibernateMappingContext 
hibernateMappingContext) {
         this.hibernateMappingContext = hibernateMappingContext;
@@ -261,7 +275,12 @@ public class HibernateMappingContextConfiguration extends 
Configuration
         ConfigurationHelper.resolvePlaceHolders(getProperties());
 
         final GrailsDomainBinder domainBinder =
-                new GrailsDomainBinder(dataSourceName, sessionFactoryBeanName, 
hibernateMappingContext);
+                new GrailsDomainBinder(
+                        dataSourceName,
+                        sessionFactoryBeanName,
+                        hibernateMappingContext,
+                        namingStrategyProvider,
+                        hibernateMappingContext.getMappingCacheHolder());
 
         List<Class> annotatedClasses = new ArrayList<>();
         for (PersistentEntity persistentEntity : 
hibernateMappingContext.getPersistentEntities()) {
diff --git 
a/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/cfg/MappingCacheHolder.java
 
b/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/cfg/MappingCacheHolder.java
index 8e3828f5b4..1083a5fdd9 100644
--- 
a/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/cfg/MappingCacheHolder.java
+++ 
b/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/cfg/MappingCacheHolder.java
@@ -27,13 +27,7 @@ import 
org.grails.orm.hibernate.cfg.domainbinding.hibernate.GrailsHibernatePersi
 /** Holder for the GORM mapping cache. */
 public class MappingCacheHolder {
 
-    private static final MappingCacheHolder INSTANCE = new 
MappingCacheHolder();
-
-    private MappingCacheHolder() {}
-
-    public static MappingCacheHolder getInstance() {
-        return INSTANCE;
-    }
+    public MappingCacheHolder() {}
 
     private final Map<Class<?>, Mapping> MAPPING_CACHE = new HashMap<>();
 
diff --git 
a/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/cfg/domainbinding/binder/GrailsDomainBinder.java
 
b/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/cfg/domainbinding/binder/GrailsDomainBinder.java
index c70e8f8417..61f40fd6b9 100644
--- 
a/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/cfg/domainbinding/binder/GrailsDomainBinder.java
+++ 
b/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/cfg/domainbinding/binder/GrailsDomainBinder.java
@@ -49,23 +49,6 @@ import 
org.grails.orm.hibernate.cfg.domainbinding.util.NamingStrategyWrapper;
 import 
org.grails.orm.hibernate.cfg.domainbinding.util.PropertyFromValueCreator;
 import 
org.grails.orm.hibernate.cfg.domainbinding.util.SimpleValueColumnFetcher;
 
-import org.grails.orm.hibernate.cfg.HibernateMappingContext;
-import org.grails.orm.hibernate.cfg.MappingCacheHolder;
-import org.grails.orm.hibernate.cfg.PersistentEntityNamingStrategy;
-import 
org.grails.orm.hibernate.cfg.domainbinding.collectionType.CollectionHolder;
-import 
org.grails.orm.hibernate.cfg.domainbinding.hibernate.HibernatePersistentEntity;
-import org.grails.orm.hibernate.cfg.domainbinding.util.BackticksRemover;
-import org.grails.orm.hibernate.cfg.domainbinding.util.BasicValueIdCreator;
-import 
org.grails.orm.hibernate.cfg.domainbinding.util.ColumnNameForPropertyAndPathFetcher;
-import 
org.grails.orm.hibernate.cfg.domainbinding.util.DefaultColumnNameFetcher;
-import org.grails.orm.hibernate.cfg.domainbinding.util.GrailsPropertyResolver;
-import org.grails.orm.hibernate.cfg.domainbinding.util.MultiTenantFilterBinder;
-import 
org.grails.orm.hibernate.cfg.domainbinding.util.MultiTenantFilterDefinitionBinder;
-import org.grails.orm.hibernate.cfg.domainbinding.util.NamingStrategyProvider;
-import org.grails.orm.hibernate.cfg.domainbinding.util.NamingStrategyWrapper;
-import 
org.grails.orm.hibernate.cfg.domainbinding.util.PropertyFromValueCreator;
-import 
org.grails.orm.hibernate.cfg.domainbinding.util.SimpleValueColumnFetcher;
-
 /**
  * Handles the binding Grails domain classes and properties to the Hibernate 
runtime meta model.
  * Based on the HbmBinder code in Hibernate core and influenced by 
AnnotationsBinder.
@@ -82,14 +65,12 @@ public class GrailsDomainBinder implements 
AdditionalMappingContributor, TypeCon
     public static final String ENUM_CLASS_PROP = "enumClass";
     public static final Logger LOG = 
LoggerFactory.getLogger(GrailsDomainBinder.class);
 
-    /** Provider for naming strategies */
-    private static final NamingStrategyProvider NAMING_STRATEGY_PROVIDER = new 
NamingStrategyProvider();
-
     public static final String JPA_DEFAULT_DISCRIMINATOR_TYPE = "DTYPE";
 
     private final String sessionFactoryName;
     private final String dataSourceName;
     private final HibernateMappingContext hibernateMappingContext;
+    private final NamingStrategyProvider namingStrategyProvider;
     private PersistentEntityNamingStrategy namingStrategy;
     private MetadataBuildingContext metadataBuildingContext;
     private final MappingCacheHolder mappingCacheHolder;
@@ -100,10 +81,20 @@ public class GrailsDomainBinder implements 
AdditionalMappingContributor, TypeCon
 
     public GrailsDomainBinder(
             String dataSourceName, String sessionFactoryName, 
HibernateMappingContext hibernateMappingContext) {
+        this(dataSourceName, sessionFactoryName, hibernateMappingContext, new 
NamingStrategyProvider(), new MappingCacheHolder());
+    }
+
+    public GrailsDomainBinder(
+            String dataSourceName,
+            String sessionFactoryName,
+            HibernateMappingContext hibernateMappingContext,
+            NamingStrategyProvider namingStrategyProvider,
+            MappingCacheHolder mappingCacheHolder) {
         this.sessionFactoryName = sessionFactoryName;
         this.dataSourceName = dataSourceName;
         this.hibernateMappingContext = hibernateMappingContext;
-        this.mappingCacheHolder = MappingCacheHolder.getInstance();
+        this.namingStrategyProvider = namingStrategyProvider;
+        this.mappingCacheHolder = mappingCacheHolder;
 
         // pre-build mappings
         for (HibernatePersistentEntity persistentEntity :
@@ -254,15 +245,15 @@ public class GrailsDomainBinder implements 
AdditionalMappingContributor, TypeCon
      * @throws InstantiationException When an error occurred instantiating the 
strategy
      * @throws IllegalAccessException When an error occurred instantiating the 
strategy
      */
-    public static void configureNamingStrategy(final String datasourceName, 
final Object strategy)
+    public void configureNamingStrategy(final String datasourceName, final 
Object strategy)
             throws ClassNotFoundException, InstantiationException, 
IllegalAccessException {
-        NAMING_STRATEGY_PROVIDER.configureNamingStrategy(datasourceName, 
strategy);
+        namingStrategyProvider.configureNamingStrategy(datasourceName, 
strategy);
     }
 
     public PersistentEntityNamingStrategy getNamingStrategy() {
         if (namingStrategy == null) {
             namingStrategy = new NamingStrategyWrapper(
-                    
NAMING_STRATEGY_PROVIDER.getPhysicalNamingStrategy(sessionFactoryName), 
getJdbcEnvironment());
+                    
namingStrategyProvider.getPhysicalNamingStrategy(sessionFactoryName), 
getJdbcEnvironment());
         }
         return namingStrategy;
     }
@@ -282,4 +273,12 @@ public class GrailsDomainBinder implements 
AdditionalMappingContributor, TypeCon
 
     @Override
     public void contribute(TypeContributions typeContributions, 
ServiceRegistry serviceRegistry) {}
+
+    /**
+     * Manually triggers the contribution process. Useful for unit testing
+     * where the full Hibernate bootstrap is not invoked.
+     */
+    public void contribute(InFlightMetadataCollector metadataCollector, 
HibernateMappingContext mappingContext) {
+        contribute(null, metadataCollector, null, 
getMetadataBuildingContext());
+    }
 }
diff --git 
a/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/connections/HibernateConnectionSourceFactory.java
 
b/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/connections/HibernateConnectionSourceFactory.java
index 1f3e0f3379..6b37b0c2f9 100644
--- 
a/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/connections/HibernateConnectionSourceFactory.java
+++ 
b/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/connections/HibernateConnectionSourceFactory.java
@@ -138,7 +138,7 @@ public class HibernateConnectionSourceFactory
         if (hibernateSettings.getPackagesToScan() != null)
             configuration.scanPackages(hibernateSettings.getPackagesToScan());
 
-        configureNamingStrategy(name, hibernateSettings);
+        configureNamingStrategy(name, configuration, hibernateSettings);
 
         ClosureEventTriggeringInterceptor eventTriggeringInterceptor =
                 
resolveEventTriggeringInterceptor(hibernateSettings.getClosureEventTriggeringInterceptorClass());
@@ -224,10 +224,14 @@ public class HibernateConnectionSourceFactory
     }
 
     private static void configureNamingStrategy(
-            String name, HibernateConnectionSourceSettings.HibernateSettings 
hibernateSettings) {
+            String name,
+            HibernateMappingContextConfiguration configuration,
+            HibernateConnectionSourceSettings.HibernateSettings 
hibernateSettings) {
         try {
             Class<? extends PhysicalNamingStrategy> namingStrategy = 
hibernateSettings.getNaming_strategy();
-            if (namingStrategy != null) 
GrailsDomainBinder.configureNamingStrategy(name, namingStrategy);
+            if (namingStrategy != null) {
+                
configuration.getNamingStrategyProvider().configureNamingStrategy(name, 
namingStrategy);
+            }
         } catch (Throwable e) {
             throw new ConfigurationException("Error configuring naming 
strategy: " + e.getMessage(), e);
         }
diff --git 
a/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/query/HibernateHqlQuery.java
 
b/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/query/HibernateHqlQuery.java
index bc9ce6a421..63cac860c9 100644
--- 
a/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/query/HibernateHqlQuery.java
+++ 
b/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/query/HibernateHqlQuery.java
@@ -209,7 +209,8 @@ public class HibernateHqlQuery extends Query {
             delegate.setCacheable(false);
         } else {
             if (!args.containsKey(HibernateQueryArgument.CACHE.value())) {
-                org.grails.orm.hibernate.cfg.Mapping m = 
org.grails.orm.hibernate.cfg.MappingCacheHolder.getInstance()
+                org.grails.orm.hibernate.cfg.Mapping m = 
((org.grails.orm.hibernate.cfg.HibernateMappingContext) 
getEntity().getMappingContext())
+                        .getMappingCacheHolder()
                         .getMapping(getEntity().getJavaClass());
                 if (m != null && m.getCache() != null && 
m.getCache().getEnabled()) {
                     delegate.setCacheable(true);
diff --git 
a/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/query/HqlListQueryBuilder.java
 
b/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/query/HqlListQueryBuilder.java
index b22b7e1d3b..b182e0f0ff 100644
--- 
a/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/query/HqlListQueryBuilder.java
+++ 
b/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/query/HqlListQueryBuilder.java
@@ -27,6 +27,7 @@ import org.grails.datastore.mapping.model.PersistentEntity;
 import org.grails.datastore.mapping.model.PersistentProperty;
 import org.grails.datastore.mapping.model.types.Association;
 import org.grails.datastore.mapping.model.types.Embedded;
+import org.grails.orm.hibernate.cfg.HibernateMappingContext;
 import org.grails.orm.hibernate.cfg.Mapping;
 import org.grails.orm.hibernate.cfg.MappingCacheHolder;
 
@@ -101,7 +102,8 @@ public class HqlListQueryBuilder {
             clauses.add(orderClause(alias, sort, dir, ignoreCase && 
isStringProp(sort)));
         } else {
             // fall back to default mapping sort
-            Mapping m = 
MappingCacheHolder.getInstance().getMapping(entity.getJavaClass());
+            MappingCacheHolder cacheHolder = ((HibernateMappingContext) 
entity.getMappingContext()).getMappingCacheHolder();
+            Mapping m = cacheHolder.getMapping(entity.getJavaClass());
             if (m != null) {
                 m.getSort()
                         .getNamesAndDirections()

Reply via email to