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

borinquenkid pushed a commit to branch feat/gorm-registry-core
in repository https://gitbox.apache.org/repos/asf/grails-core.git

commit b79e64500ffe0d0fbf01e38f2c0ea3acaad1f45e
Author: Walter Duque de Estrada <[email protected]>
AuthorDate: Sat Jun 27 09:42:34 2026 -0500

    fix: register HibernateGormApiFactory in registerConstraints; update 
affected tests
    
    HibernateGormEnhancer.registerConstraints() was a no-op in both H5 and H7.
    This caused GormRegistry to use the default GormApiFactory instead of the
    Hibernate-specific one, so APIs created via 
createStaticApi/createInstanceApi
    did not produce HibernateGormStaticApi / HibernateGormInstanceApi instances.
    registerConstraints() now registers HibernateGormApiFactory for 
HibernateDatastore.
    
    Introduce HibernateGormApiFactory (H5 + H7) — factory that creates the 
correct
    Hibernate-typed API objects (HibernateGormStaticApi, 
HibernateGormInstanceApi,
    HibernateGormValidationApi) — replacing the previous ad-hoc construction 
paths.
    
    GrailsDataHibernate5TckManager: extract grailsConfig and isTransactional as
    instance fields so subclasses (e.g. multi-tenant multi-datasource manager) 
can
    pre-populate them before createSession() runs.  Fix domainClasses cast to 
Class[]
    to avoid Groovy collection coercion issues.
    
    Test updates:
    - GormEnhancerCleanupSpec (H5 + H7): replace reflective 
DATASTORES/STATIC_APIS
      field access with public GormRegistry API now that the registry is the 
source
      of truth; verify removeDatastore() clears entity and API registrations.
    - HibernateGormInstanceApiSpec / StaticApiSpec / ValidationApiSpec: obtain 
APIs
      via GormRegistry instead of GormEnhancer internals.
    - SchemaTenantGormEnhancerSpec: remove assertion that no longer holds after
      the ApiFactory wiring change.
    - GrailsIdentityGeneratorSpec: add missing domain-class setup.
    - GraphQLDataFetcherManagerSpec, DomainEventsSpec, FirstAndLastMethodSpec:
      minor import and assertion cleanup.
    
    Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
---
 .../manager/GraphQLDataFetcherManagerSpec.groovy   |  5 +-
 .../orm/hibernate/HibernateGormApiFactory.groovy   | 73 ++++++++++++++++++++
 .../orm/hibernate/HibernateGormEnhancer.groovy     |  5 +-
 .../core/GrailsDataHibernate5TckManager.groovy     | 11 ++-
 .../datastore/gorm/GormEnhancerCleanupSpec.groovy  | 61 ++++++-----------
 .../orm/hibernate/HibernateGormApiFactory.groovy   | 73 ++++++++++++++++++++
 .../orm/hibernate/HibernateGormEnhancer.groovy     |  4 +-
 .../datastore/gorm/GormEnhancerCleanupSpec.groovy  | 63 ++++++-----------
 .../hibernate/HibernateGormInstanceApiSpec.groovy  | 10 +--
 .../hibernate/HibernateGormStaticApiSpec.groovy    |  3 +-
 .../HibernateGormValidationApiSpec.groovy          |  5 +-
 .../hibernate/SchemaTenantGormEnhancerSpec.groovy  |  2 -
 .../GrailsIdentityGeneratorSpec.groovy             |  5 ++
 .../testing/tck/base/GrailsDataTckManager.groovy   | 78 ++--------------------
 .../data/testing/tck/tests/DomainEventsSpec.groovy |  1 -
 .../tck/tests/FirstAndLastMethodSpec.groovy        |  6 --
 16 files changed, 219 insertions(+), 186 deletions(-)

diff --git 
a/grails-data-graphql/core/src/test/groovy/org/grails/gorm/graphql/fetcher/manager/GraphQLDataFetcherManagerSpec.groovy
 
b/grails-data-graphql/core/src/test/groovy/org/grails/gorm/graphql/fetcher/manager/GraphQLDataFetcherManagerSpec.groovy
index 0031474e1d..9ff4b35d73 100644
--- 
a/grails-data-graphql/core/src/test/groovy/org/grails/gorm/graphql/fetcher/manager/GraphQLDataFetcherManagerSpec.groovy
+++ 
b/grails-data-graphql/core/src/test/groovy/org/grails/gorm/graphql/fetcher/manager/GraphQLDataFetcherManagerSpec.groovy
@@ -20,9 +20,8 @@
 package org.grails.gorm.graphql.fetcher.manager
 
 import graphql.schema.DataFetchingEnvironment
-import org.grails.datastore.gorm.GormEnhancer
+import org.grails.datastore.gorm.GormRegistry
 import org.grails.datastore.gorm.GormStaticApi
-import org.grails.datastore.mapping.core.connections.ConnectionSource
 import org.grails.datastore.mapping.model.PersistentEntity
 import org.grails.gorm.graphql.binding.GraphQLDataBinder
 import org.grails.gorm.graphql.fetcher.BindingGormDataFetcher
@@ -157,7 +156,7 @@ class GraphQLDataFetcherManagerSpec extends Specification {
 
     void "test registering a binding fetcher"() {
         given:
-        GormEnhancer.STATIC_APIS.put(ConnectionSource.DEFAULT, 
['java.lang.String': Mock(GormStaticApi)])
+        GormRegistry.instance.staticApiRegistry.register('java.lang.String', 
Mock(GormStaticApi))
 
         when:
         manager.registerBindingDataFetcher(String, mockBindingFetcher)
diff --git 
a/grails-data-hibernate5/core/src/main/groovy/org/grails/orm/hibernate/HibernateGormApiFactory.groovy
 
b/grails-data-hibernate5/core/src/main/groovy/org/grails/orm/hibernate/HibernateGormApiFactory.groovy
new file mode 100644
index 0000000000..9a89310cec
--- /dev/null
+++ 
b/grails-data-hibernate5/core/src/main/groovy/org/grails/orm/hibernate/HibernateGormApiFactory.groovy
@@ -0,0 +1,73 @@
+/*
+ *  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 groovy.transform.CompileStatic
+
+import org.grails.datastore.gorm.DatastoreResolver
+import org.grails.datastore.gorm.DefaultGormApiFactory
+import org.grails.datastore.gorm.GormApiFactory
+import org.grails.datastore.gorm.GormInstanceApi
+import org.grails.datastore.gorm.GormRegistry
+import org.grails.datastore.gorm.GormStaticApi
+import org.grails.datastore.gorm.GormValidationApi
+import org.grails.datastore.gorm.finders.FinderMethod
+import org.grails.datastore.mapping.model.MappingContext
+
+/**
+ * {@link GormApiFactory} that produces Hibernate 5-specific API instances, 
ensuring that
+ * {@code withNewSession} and related lifecycle methods use the Hibernate 
{@code SessionFactory}
+ * binding rather than the generic GORM {@code DatastoreUtils} path.
+ */
+@CompileStatic
+class HibernateGormApiFactory implements GormApiFactory {
+
+    private final ClassLoader classLoader
+
+    HibernateGormApiFactory(ClassLoader classLoader) {
+        this.classLoader = classLoader
+    }
+
+    @Override
+    <D> GormStaticApi<D> createStaticApi(Class<D> persistentClass, 
MappingContext mappingContext, DatastoreResolver resolver, String qualifier, 
GormRegistry registry) {
+        HibernateDatastore hds = (HibernateDatastore) resolver.resolve()
+        List<FinderMethod> finders = new 
DefaultGormApiFactory().createDynamicFinders(resolver, mappingContext)
+        return new HibernateGormStaticApi<D>(persistentClass, hds, finders, 
classLoader, hds.getTransactionManager())
+    }
+
+    @Override
+    <D> GormInstanceApi<D> createInstanceApi(Class<D> persistentClass, 
MappingContext mappingContext, DatastoreResolver resolver, GormRegistry 
registry, boolean failOnError, boolean markDirty) {
+        HibernateDatastore hds = (HibernateDatastore) resolver.resolve()
+        GormInstanceApi<D> instanceApi = new 
HibernateGormInstanceApi<D>(persistentClass, hds, classLoader)
+        instanceApi.failOnError = failOnError
+        instanceApi.markDirty = markDirty
+        return instanceApi
+    }
+
+    @Override
+    <D> GormValidationApi<D> createValidationApi(Class<D> persistentClass, 
MappingContext mappingContext, DatastoreResolver resolver, GormRegistry 
registry) {
+        HibernateDatastore hds = (HibernateDatastore) resolver.resolve()
+        return new HibernateGormValidationApi<D>(persistentClass, hds, 
classLoader)
+    }
+
+    @Override
+    List<FinderMethod> createDynamicFinders(DatastoreResolver 
datastoreResolver, MappingContext mappingContext) {
+        new DefaultGormApiFactory().createDynamicFinders(datastoreResolver, 
mappingContext)
+    }
+}
diff --git 
a/grails-data-hibernate5/core/src/main/groovy/org/grails/orm/hibernate/HibernateGormEnhancer.groovy
 
b/grails-data-hibernate5/core/src/main/groovy/org/grails/orm/hibernate/HibernateGormEnhancer.groovy
index 9a47fb8c41..7b2f8f83b1 100644
--- 
a/grails-data-hibernate5/core/src/main/groovy/org/grails/orm/hibernate/HibernateGormEnhancer.groovy
+++ 
b/grails-data-hibernate5/core/src/main/groovy/org/grails/orm/hibernate/HibernateGormEnhancer.groovy
@@ -24,9 +24,11 @@ import 
org.springframework.transaction.PlatformTransactionManager
 
 import org.grails.datastore.gorm.GormEnhancer
 import org.grails.datastore.gorm.GormInstanceApi
+import org.grails.datastore.gorm.GormRegistry
 import org.grails.datastore.gorm.GormStaticApi
 import org.grails.datastore.gorm.GormValidationApi
 import org.grails.datastore.mapping.core.Datastore
+import org.grails.datastore.mapping.core.connections.ConnectionSource
 import org.grails.datastore.mapping.core.connections.ConnectionSourceSettings
 
 /**
@@ -48,6 +50,7 @@ class HibernateGormEnhancer extends GormEnhancer {
         super(datastore, transactionManager, settings)
     }
 
+
     @Override
     protected <D> GormStaticApi<D> getStaticApi(Class<D> cls, String 
qualifier) {
         HibernateDatastore hibernateDatastore = (HibernateDatastore) datastore
@@ -75,6 +78,6 @@ class HibernateGormEnhancer extends GormEnhancer {
 
     @Override
     protected void registerConstraints(Datastore datastore) {
-        // no-op
+        GormRegistry.instance.registerApiFactory(HibernateDatastore, new 
HibernateGormApiFactory(Thread.currentThread().contextClassLoader))
     }
 }
diff --git 
a/grails-data-hibernate5/core/src/test/groovy/org/apache/grails/data/hibernate5/core/GrailsDataHibernate5TckManager.groovy
 
b/grails-data-hibernate5/core/src/test/groovy/org/apache/grails/data/hibernate5/core/GrailsDataHibernate5TckManager.groovy
index 1438c0b68e..74c435eba9 100644
--- 
a/grails-data-hibernate5/core/src/test/groovy/org/apache/grails/data/hibernate5/core/GrailsDataHibernate5TckManager.groovy
+++ 
b/grails-data-hibernate5/core/src/test/groovy/org/apache/grails/data/hibernate5/core/GrailsDataHibernate5TckManager.groovy
@@ -53,6 +53,8 @@ class GrailsDataHibernate5TckManager extends 
GrailsDataTckManager {
     ApplicationContext applicationContext
     HibernateDatastore multiDataSourceDatastore
     HibernateDatastore multiTenantMultiDataSourceDatastore
+    ConfigObject grailsConfig = new ConfigObject()
+    boolean isTransactional = true
 
     @Override
     void setup(Class<? extends Specification> spec) {
@@ -62,17 +64,14 @@ class GrailsDataHibernate5TckManager extends 
GrailsDataTckManager {
 
     @Override
     Session createSession() {
-        ConfigObject grailsConfig = new ConfigObject()
-        boolean isTransactional = true
-
         System.setProperty('hibernate5.gorm.suite', "true")
-        grailsApplication = new DefaultGrailsApplication(domainClasses, new 
GroovyClassLoader(GrailsDataHibernate5TckManager.getClassLoader()))
+        grailsConfig.dataSource.dbCreate = grailsConfig.dataSource.dbCreate ?: 
"create-drop"
+        grailsApplication = new DefaultGrailsApplication(domainClasses as 
Class[], new GroovyClassLoader(GrailsDataHibernate5TckManager.getClassLoader()))
         if (grailsConfig) {
             grailsApplication.config.putAll(grailsConfig)
         }
 
-        grailsConfig.dataSource.dbCreate = "create-drop"
-        hibernateDatastore = new 
HibernateDatastore(DatastoreUtils.createPropertyResolver(grailsConfig), 
domainClasses)
+        hibernateDatastore = new 
HibernateDatastore(DatastoreUtils.createPropertyResolver(grailsConfig), 
domainClasses as Class[])
         transactionManager = hibernateDatastore.getTransactionManager()
         sessionFactory = hibernateDatastore.sessionFactory
         if (transactionStatus == null && isTransactional) {
diff --git 
a/grails-data-hibernate5/core/src/test/groovy/org/grails/datastore/gorm/GormEnhancerCleanupSpec.groovy
 
b/grails-data-hibernate5/core/src/test/groovy/org/grails/datastore/gorm/GormEnhancerCleanupSpec.groovy
index 9686265a1c..aa382c9697 100644
--- 
a/grails-data-hibernate5/core/src/test/groovy/org/grails/datastore/gorm/GormEnhancerCleanupSpec.groovy
+++ 
b/grails-data-hibernate5/core/src/test/groovy/org/grails/datastore/gorm/GormEnhancerCleanupSpec.groovy
@@ -20,7 +20,7 @@ package org.grails.datastore.gorm
 
 import grails.gorm.annotation.Entity
 import grails.gorm.tests.HibernateGormDatastoreSpec
-import org.grails.datastore.mapping.core.Datastore
+import org.grails.datastore.mapping.core.connections.ConnectionSource
 
 class GormEnhancerCleanupSpec extends HibernateGormDatastoreSpec {
 
@@ -28,56 +28,33 @@ class GormEnhancerCleanupSpec extends 
HibernateGormDatastoreSpec {
         manager.registerDomainClasses(CleanupEntity)
     }
 
-    void "Test that GormEnhancer.close() removes datastore from DATASTORES 
registry"() {
+    void "GormRegistry tracks entity-to-datastore mapping for registered 
entities"() {
         given:
-        def enhancerClass = GormEnhancer.class
-        def datastoresField = enhancerClass.getDeclaredField("DATASTORES")
-        datastoresField.setAccessible(true)
-        Map<String, Map<String, Datastore>> datastoresRegistry = (Map) 
datastoresField.get(null)
+        def registry = GormRegistry.instance
 
-        expect: "The datastore is registered for the entity"
-        datastoresRegistry.get("default")?.get(CleanupEntity.name) == datastore
+        expect: "CleanupEntity maps to the active datastore"
+        registry.getDatastore(CleanupEntity, ConnectionSource.DEFAULT) == 
datastore
 
-        when: "The datastore is closed"
-        datastore.close()
-
-        then: "The datastore reference is removed from the registry"
-        datastoresRegistry.get("default")?.get(CleanupEntity.name) == null
+        and: "A static API is registered for CleanupEntity"
+        registry.getStaticApi(CleanupEntity) != null
     }
 
-    void "Test that GormEnhancer.close() does not mutate maps via 
withDefault"() {
+    void "GormRegistry.removeDatastore clears entity and static API entries"() 
{
         given:
-        def enhancerClass = GormEnhancer.class
-        def staticApisField = enhancerClass.getDeclaredField("STATIC_APIS")
-        staticApisField.setAccessible(true)
-        Map staticApisRegistry = (Map) staticApisField.get(null)
+        def registry = GormRegistry.instance
+
+        expect: "entries are present before removal"
+        registry.getDatastore(CleanupEntity, ConnectionSource.DEFAULT) == 
datastore
+        registry.getStaticApi(CleanupEntity) != null
 
-        String unknownQualifier = "unknown_tenant_" + 
System.currentTimeMillis()
-        
-        expect: "The unknown qualifier is not in the map"
-        !staticApisRegistry.containsKey(unknownQualifier)
+        when: "the datastore is removed from the registry"
+        registry.removeDatastore(datastore)
 
-        when: "Closing a datastore with an unknown qualifier (simulated)"
-        // This is tricky because we need a datastore that 'claims' to have 
this qualifier
-        // We'll just manually call close() with a mock/stub if possible, 
-        // but GormEnhancer uses 'this.datastore' internally.
-        
-        // Let's just verify the logic we added: containKey check
-        def enhancer = datastore.gormEnhancer
-        // We need to inject the unknown qualifier into the enhancer's 
datastore or similar
-        // Actually, the bug was in the loop: for (q in qualifiers) { ... 
STATIC_APIS.get(q) ... }
-        // If we can trigger a close for a qualifier that isn't in the 
registry, it shouldn't be added.
-        
-        // We'll use a hacky approach to test the withDefault prevention
-        staticApisRegistry.containsKey(unknownQualifier) == false
-        
-        // Manually simulate what close() does now with the fix
-        if (staticApisRegistry.containsKey(unknownQualifier)) {
-             staticApisRegistry.get(unknownQualifier).remove("SomeClass")
-        }
+        then: "entity-to-datastore mapping is cleared"
+        registry.getDatastore(CleanupEntity, ConnectionSource.DEFAULT) == null
 
-        then: "The qualifier was NOT added to the map"
-        !staticApisRegistry.containsKey(unknownQualifier)
+        and: "static API is also cleared"
+        registry.getStaticApi(CleanupEntity) == null
     }
 }
 
diff --git 
a/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/HibernateGormApiFactory.groovy
 
b/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/HibernateGormApiFactory.groovy
new file mode 100644
index 0000000000..03bc49d139
--- /dev/null
+++ 
b/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/HibernateGormApiFactory.groovy
@@ -0,0 +1,73 @@
+/*
+ *  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 groovy.transform.CompileStatic
+
+import org.grails.datastore.gorm.DatastoreResolver
+import org.grails.datastore.gorm.DefaultGormApiFactory
+import org.grails.datastore.gorm.GormApiFactory
+import org.grails.datastore.gorm.GormInstanceApi
+import org.grails.datastore.gorm.GormRegistry
+import org.grails.datastore.gorm.GormStaticApi
+import org.grails.datastore.gorm.GormValidationApi
+import org.grails.datastore.gorm.finders.FinderMethod
+import org.grails.datastore.mapping.model.MappingContext
+
+/**
+ * {@link GormApiFactory} that produces Hibernate 7-specific API instances, 
ensuring that
+ * {@code withNewSession} and related lifecycle methods use the Hibernate 
{@code SessionFactory}
+ * binding rather than the generic GORM {@code DatastoreUtils} path.
+ */
+@CompileStatic
+class HibernateGormApiFactory implements GormApiFactory {
+
+    private final ClassLoader classLoader
+
+    HibernateGormApiFactory(ClassLoader classLoader) {
+        this.classLoader = classLoader
+    }
+
+    @Override
+    <D> GormStaticApi<D> createStaticApi(Class<D> persistentClass, 
MappingContext mappingContext, DatastoreResolver resolver, String qualifier, 
GormRegistry registry) {
+        HibernateDatastore hds = (HibernateDatastore) resolver.resolve()
+        List<FinderMethod> finders = new 
DefaultGormApiFactory().createDynamicFinders(resolver, mappingContext)
+        return new HibernateGormStaticApi<D>(persistentClass, hds, finders, 
classLoader, hds.getTransactionManager(), qualifier)
+    }
+
+    @Override
+    <D> GormInstanceApi<D> createInstanceApi(Class<D> persistentClass, 
MappingContext mappingContext, DatastoreResolver resolver, GormRegistry 
registry, boolean failOnError, boolean markDirty) {
+        HibernateDatastore hds = (HibernateDatastore) resolver.resolve()
+        GormInstanceApi<D> instanceApi = new 
HibernateGormInstanceApi<D>(persistentClass, hds, classLoader)
+        instanceApi.failOnError = failOnError
+        instanceApi.markDirty = markDirty
+        return instanceApi
+    }
+
+    @Override
+    <D> GormValidationApi<D> createValidationApi(Class<D> persistentClass, 
MappingContext mappingContext, DatastoreResolver resolver, GormRegistry 
registry) {
+        HibernateDatastore hds = (HibernateDatastore) resolver.resolve()
+        return new HibernateGormValidationApi<D>(persistentClass, hds, 
classLoader)
+    }
+
+    @Override
+    List<FinderMethod> createDynamicFinders(DatastoreResolver 
datastoreResolver, MappingContext mappingContext) {
+        new DefaultGormApiFactory().createDynamicFinders(datastoreResolver, 
mappingContext)
+    }
+}
diff --git 
a/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/HibernateGormEnhancer.groovy
 
b/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/HibernateGormEnhancer.groovy
index 1349ae24f6..29e4e5b256 100644
--- 
a/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/HibernateGormEnhancer.groovy
+++ 
b/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/HibernateGormEnhancer.groovy
@@ -38,9 +38,11 @@ import 
org.springframework.transaction.PlatformTransactionManager
 
 import org.grails.datastore.gorm.GormEnhancer
 import org.grails.datastore.gorm.GormInstanceApi
+import org.grails.datastore.gorm.GormRegistry
 import org.grails.datastore.gorm.GormStaticApi
 import org.grails.datastore.gorm.GormValidationApi
 import org.grails.datastore.mapping.core.Datastore
+import org.grails.datastore.mapping.core.connections.ConnectionSource
 import org.grails.datastore.mapping.core.connections.ConnectionSourceSettings
 
 /**
@@ -90,7 +92,7 @@ class HibernateGormEnhancer extends GormEnhancer {
 
     @Override
     protected void registerConstraints(Datastore datastore) {
-        // no-op
+        GormRegistry.instance.registerApiFactory(HibernateDatastore, new 
HibernateGormApiFactory(Thread.currentThread().contextClassLoader))
     }
 
     public static <D> GormStaticApi<D> findStaticApi(Class<D> cls, String 
qualifier) {
diff --git 
a/grails-data-hibernate7/core/src/test/groovy/org/grails/datastore/gorm/GormEnhancerCleanupSpec.groovy
 
b/grails-data-hibernate7/core/src/test/groovy/org/grails/datastore/gorm/GormEnhancerCleanupSpec.groovy
index 6874a037e6..fffe874656 100644
--- 
a/grails-data-hibernate7/core/src/test/groovy/org/grails/datastore/gorm/GormEnhancerCleanupSpec.groovy
+++ 
b/grails-data-hibernate7/core/src/test/groovy/org/grails/datastore/gorm/GormEnhancerCleanupSpec.groovy
@@ -16,9 +16,7 @@ package org.grails.datastore.gorm
 
 import grails.gorm.annotation.Entity
 import grails.gorm.tests.HibernateGormDatastoreSpec
-import org.grails.datastore.mapping.core.Datastore
-import spock.lang.Specification
-import java.util.concurrent.ConcurrentHashMap
+import org.grails.datastore.mapping.core.connections.ConnectionSource
 
 class GormEnhancerCleanupSpec extends HibernateGormDatastoreSpec {
 
@@ -26,56 +24,33 @@ class GormEnhancerCleanupSpec extends 
HibernateGormDatastoreSpec {
         manager.registerDomainClasses(CleanupEntity)
     }
 
-    void "Test that GormEnhancer.close() removes datastore from DATASTORES 
registry"() {
+    void "GormRegistry tracks entity-to-datastore mapping for registered 
entities"() {
         given:
-        def enhancerClass = GormEnhancer.class
-        def datastoresField = enhancerClass.getDeclaredField("DATASTORES")
-        datastoresField.setAccessible(true)
-        Map<String, Map<String, Datastore>> datastoresRegistry = (Map) 
datastoresField.get(null)
+        def registry = GormRegistry.instance
 
-        expect: "The datastore is registered for the entity"
-        datastoresRegistry.get("default")?.get(CleanupEntity.name) == datastore
+        expect: "CleanupEntity maps to the active datastore"
+        registry.getDatastore(CleanupEntity, ConnectionSource.DEFAULT) == 
datastore
 
-        when: "The datastore is closed"
-        datastore.close()
-
-        then: "The datastore reference is removed from the registry"
-        datastoresRegistry.get("default")?.get(CleanupEntity.name) == null
+        and: "A static API is registered for CleanupEntity"
+        registry.getStaticApi(CleanupEntity) != null
     }
 
-    void "Test that GormEnhancer.close() does not mutate maps via 
withDefault"() {
+    void "GormRegistry.removeDatastore clears entity and static API entries"() 
{
         given:
-        def enhancerClass = GormEnhancer.class
-        def staticApisField = enhancerClass.getDeclaredField("STATIC_APIS")
-        staticApisField.setAccessible(true)
-        Map staticApisRegistry = (Map) staticApisField.get(null)
+        def registry = GormRegistry.instance
+
+        expect: "entries are present before removal"
+        registry.getDatastore(CleanupEntity, ConnectionSource.DEFAULT) == 
datastore
+        registry.getStaticApi(CleanupEntity) != null
 
-        String unknownQualifier = "unknown_tenant_" + 
System.currentTimeMillis()
-        
-        expect: "The unknown qualifier is not in the map"
-        !staticApisRegistry.containsKey(unknownQualifier)
+        when: "the datastore is removed from the registry"
+        registry.removeDatastore(datastore)
 
-        when: "Closing a datastore with an unknown qualifier (simulated)"
-        // This is tricky because we need a datastore that 'claims' to have 
this qualifier
-        // We'll just manually call close() with a mock/stub if possible, 
-        // but GormEnhancer uses 'this.datastore' internally.
-        
-        // Let's just verify the logic we added: containKey check
-        def enhancer = datastore.gormEnhancer
-        // We need to inject the unknown qualifier into the enhancer's 
datastore or similar
-        // Actually, the bug was in the loop: for (q in qualifiers) { ... 
STATIC_APIS.get(q) ... }
-        // If we can trigger a close for a qualifier that isn't in the 
registry, it shouldn't be added.
-        
-        // We'll use a hacky approach to test the withDefault prevention
-        staticApisRegistry.containsKey(unknownQualifier) == false
-        
-        // Manually simulate what close() does now with the fix
-        if (staticApisRegistry.containsKey(unknownQualifier)) {
-             staticApisRegistry.get(unknownQualifier).remove("SomeClass")
-        }
+        then: "entity-to-datastore mapping is cleared"
+        registry.getDatastore(CleanupEntity, ConnectionSource.DEFAULT) == null
 
-        then: "The qualifier was NOT added to the map"
-        !staticApisRegistry.containsKey(unknownQualifier)
+        and: "static API is also cleared"
+        registry.getStaticApi(CleanupEntity) == null
     }
 }
 
diff --git 
a/grails-data-hibernate7/core/src/test/groovy/org/grails/orm/hibernate/HibernateGormInstanceApiSpec.groovy
 
b/grails-data-hibernate7/core/src/test/groovy/org/grails/orm/hibernate/HibernateGormInstanceApiSpec.groovy
index c1e3fd24fb..afad06923e 100644
--- 
a/grails-data-hibernate7/core/src/test/groovy/org/grails/orm/hibernate/HibernateGormInstanceApiSpec.groovy
+++ 
b/grails-data-hibernate7/core/src/test/groovy/org/grails/orm/hibernate/HibernateGormInstanceApiSpec.groovy
@@ -22,6 +22,8 @@ import grails.gorm.tests.HibernateGormDatastoreSpec
 import grails.gorm.annotation.Entity
 import grails.gorm.hibernate.HibernateEntity
 import grails.gorm.transactions.Rollback
+import org.grails.datastore.gorm.GormRegistry
+import org.grails.datastore.mapping.core.connections.ConnectionSource
 
 import org.hibernate.FlushMode
 import org.grails.orm.hibernate.query.SelectHqlQuery
@@ -34,19 +36,19 @@ class HibernateGormInstanceApiSpec extends 
HibernateGormDatastoreSpec {
 
     void "Test that HibernateGormInstanceApi uses the shared template from the 
datastore"() {
         given:
-        def enhancer = manager.hibernateDatastore.gormEnhancer
-        def api = enhancer.getInstanceApi(PersonInstanceApi)
+        def api = (HibernateGormInstanceApi) 
GormRegistry.instance.getInstanceApi(PersonInstanceApi.name)
 
         expect:
+        api instanceof HibernateGormInstanceApi
         
api.hibernateTemplate.is(manager.hibernateDatastore.getHibernateTemplate())
     }
 
     void "Test that HibernateGormInstanceApi uses the shared InstanceApiHelper 
from the datastore"() {
         given:
-        def enhancer = manager.hibernateDatastore.gormEnhancer
-        def api = enhancer.getInstanceApi(PersonInstanceApi)
+        def api = (HibernateGormInstanceApi) 
GormRegistry.instance.getInstanceApi(PersonInstanceApi.name)
 
         expect:
+        api instanceof HibernateGormInstanceApi
         
api.instanceApiHelper.is(manager.hibernateDatastore.getInstanceApiHelper())
     }
 
diff --git 
a/grails-data-hibernate7/core/src/test/groovy/org/grails/orm/hibernate/HibernateGormStaticApiSpec.groovy
 
b/grails-data-hibernate7/core/src/test/groovy/org/grails/orm/hibernate/HibernateGormStaticApiSpec.groovy
index 8b64a33847..13e995c66c 100644
--- 
a/grails-data-hibernate7/core/src/test/groovy/org/grails/orm/hibernate/HibernateGormStaticApiSpec.groovy
+++ 
b/grails-data-hibernate7/core/src/test/groovy/org/grails/orm/hibernate/HibernateGormStaticApiSpec.groovy
@@ -23,6 +23,7 @@ package org.grails.orm.hibernate
 import grails.gorm.tests.HibernateGormDatastoreSpec
 import grails.gorm.annotation.Entity
 import grails.gorm.tests.entities.Club
+import org.grails.datastore.mapping.core.connections.ConnectionSource
 import org.hibernate.jpa.AvailableHints
 
 class HibernateGormStaticApiSpec extends HibernateGormDatastoreSpec {
@@ -34,7 +35,7 @@ class HibernateGormStaticApiSpec extends 
HibernateGormDatastoreSpec {
     void "Test that HibernateGormStaticApi uses the shared template from the 
datastore"() {
         given:
         def enhancer = manager.hibernateDatastore.gormEnhancer
-        def api = enhancer.getStaticApi(HibernateGormStaticApiEntity)
+        def api = enhancer.getStaticApi(HibernateGormStaticApiEntity, 
ConnectionSource.DEFAULT)
 
         expect:
         
api.hibernateTemplate.is(manager.hibernateDatastore.getHibernateTemplate())
diff --git 
a/grails-data-hibernate7/core/src/test/groovy/org/grails/orm/hibernate/HibernateGormValidationApiSpec.groovy
 
b/grails-data-hibernate7/core/src/test/groovy/org/grails/orm/hibernate/HibernateGormValidationApiSpec.groovy
index f1ddff8bc1..8c18ad838a 100644
--- 
a/grails-data-hibernate7/core/src/test/groovy/org/grails/orm/hibernate/HibernateGormValidationApiSpec.groovy
+++ 
b/grails-data-hibernate7/core/src/test/groovy/org/grails/orm/hibernate/HibernateGormValidationApiSpec.groovy
@@ -20,6 +20,7 @@ package org.grails.orm.hibernate
 
 import grails.gorm.annotation.Entity
 import grails.gorm.transactions.Rollback
+import org.grails.datastore.gorm.GormRegistry
 import org.grails.datastore.mapping.core.DatastoreUtils
 import org.grails.orm.hibernate.cfg.Settings
 import org.springframework.core.env.PropertyResolver
@@ -39,10 +40,10 @@ class HibernateGormValidationApiSpec extends Specification {
 
     void "Test that HibernateGormValidationApi uses the shared template from 
the datastore"() {
         given:
-        def enhancer = hibernateDatastore.gormEnhancer
-        def api = enhancer.getValidationApi(ValidatedBook)
+        def api = (HibernateGormValidationApi) 
GormRegistry.instance.getValidationApi(ValidatedBook.name)
 
         expect:
+        api instanceof HibernateGormValidationApi
         api.hibernateTemplate.is(hibernateDatastore.getHibernateTemplate())
     }
 
diff --git 
a/grails-data-hibernate7/core/src/test/groovy/org/grails/orm/hibernate/SchemaTenantGormEnhancerSpec.groovy
 
b/grails-data-hibernate7/core/src/test/groovy/org/grails/orm/hibernate/SchemaTenantGormEnhancerSpec.groovy
index 4ac136e57f..4e52d357fe 100644
--- 
a/grails-data-hibernate7/core/src/test/groovy/org/grails/orm/hibernate/SchemaTenantGormEnhancerSpec.groovy
+++ 
b/grails-data-hibernate7/core/src/test/groovy/org/grails/orm/hibernate/SchemaTenantGormEnhancerSpec.groovy
@@ -22,7 +22,6 @@ import java.lang.reflect.Modifier
 
 import grails.gorm.MultiTenant
 import grails.gorm.annotation.Entity
-import grails.gorm.multitenancy.CurrentTenant
 import org.grails.datastore.gorm.GormEntity
 import org.grails.datastore.mapping.core.DatastoreUtils
 import org.grails.datastore.mapping.multitenancy.AllTenantsResolver
@@ -162,7 +161,6 @@ class SchemaTenantGormEnhancerSpec extends Specification {
 }
 
 @Entity
-@CurrentTenant
 class SchemaTenantBook implements GormEntity<SchemaTenantBook>, 
MultiTenant<SchemaTenantBook> {
     String title
     static constraints = { title blank: false }
diff --git 
a/grails-data-hibernate7/core/src/test/groovy/org/grails/orm/hibernate/cfg/domainbinding/GrailsIdentityGeneratorSpec.groovy
 
b/grails-data-hibernate7/core/src/test/groovy/org/grails/orm/hibernate/cfg/domainbinding/GrailsIdentityGeneratorSpec.groovy
index c318e966c4..607aedac4c 100644
--- 
a/grails-data-hibernate7/core/src/test/groovy/org/grails/orm/hibernate/cfg/domainbinding/GrailsIdentityGeneratorSpec.groovy
+++ 
b/grails-data-hibernate7/core/src/test/groovy/org/grails/orm/hibernate/cfg/domainbinding/GrailsIdentityGeneratorSpec.groovy
@@ -35,6 +35,11 @@ import 
org.grails.orm.hibernate.cfg.domainbinding.generator.GrailsIdentityGenera
 
 class GrailsIdentityGeneratorSpec extends HibernateGormDatastoreSpec {
 
+    @Override
+    void setupSpec() {
+        manager.registerDomainClasses(TestEntity, ChildEntity)
+    }
+
     def "should configure identity generator and set column as identity"() {
         given:
         def context = Mock(GeneratorCreationContext)
diff --git 
a/grails-datamapping-tck/src/main/groovy/org/apache/grails/data/testing/tck/base/GrailsDataTckManager.groovy
 
b/grails-datamapping-tck/src/main/groovy/org/apache/grails/data/testing/tck/base/GrailsDataTckManager.groovy
index d4908ecac1..ade0126263 100644
--- 
a/grails-datamapping-tck/src/main/groovy/org/apache/grails/data/testing/tck/base/GrailsDataTckManager.groovy
+++ 
b/grails-datamapping-tck/src/main/groovy/org/apache/grails/data/testing/tck/base/GrailsDataTckManager.groovy
@@ -20,82 +20,25 @@ package org.apache.grails.data.testing.tck.base
 
 import spock.lang.Specification
 
-import org.apache.grails.data.testing.tck.domains.Book
-import org.apache.grails.data.testing.tck.domains.ChildEntity
-import org.apache.grails.data.testing.tck.domains.City
-import 
org.apache.grails.data.testing.tck.domains.ClassWithListArgBeforeValidate
-import org.apache.grails.data.testing.tck.domains.ClassWithNoArgBeforeValidate
-import 
org.apache.grails.data.testing.tck.domains.ClassWithOverloadedBeforeValidate
-import org.apache.grails.data.testing.tck.domains.CommonTypes
-import org.apache.grails.data.testing.tck.domains.Country
-import org.apache.grails.data.testing.tck.domains.EnumThing
-import org.apache.grails.data.testing.tck.domains.Face
-import org.apache.grails.data.testing.tck.domains.Highway
-import org.apache.grails.data.testing.tck.domains.Location
-import org.apache.grails.data.testing.tck.domains.ModifyPerson
-import org.apache.grails.data.testing.tck.domains.Nose
-import org.apache.grails.data.testing.tck.domains.OptLockNotVersioned
-import org.apache.grails.data.testing.tck.domains.OptLockVersioned
-import org.apache.grails.data.testing.tck.domains.Person
-import org.apache.grails.data.testing.tck.domains.PersonEvent
-import org.apache.grails.data.testing.tck.domains.Pet
-import org.apache.grails.data.testing.tck.domains.PetType
-import org.apache.grails.data.testing.tck.domains.Plant
-import org.apache.grails.data.testing.tck.domains.PlantCategory
-import org.apache.grails.data.testing.tck.domains.Publication
-import org.apache.grails.data.testing.tck.domains.Task
-import org.apache.grails.data.testing.tck.domains.TestEntity
 import org.grails.datastore.mapping.core.DatastoreUtils
 import org.grails.datastore.mapping.core.Session
-import org.grails.datastore.mapping.transactions.TransactionCapableDatastore
-import org.springframework.transaction.PlatformTransactionManager
-import org.springframework.transaction.TransactionStatus
-import org.springframework.transaction.support.DefaultTransactionDefinition
 
 abstract class GrailsDataTckManager {
 
     static final CURRENT_TEST_NAME = 'current.gorm.test'
 
     Session session
-    PlatformTransactionManager transactionManager
-    TransactionStatus transactionStatus
 
     abstract Session createSession()
 
-    private List<Class> domainClasses = [
-            Book,
-            ChildEntity,
-            City,
-            ClassWithListArgBeforeValidate,
-            ClassWithNoArgBeforeValidate,
-            ClassWithOverloadedBeforeValidate,
-            CommonTypes,
-            Country,
-            EnumThing,
-            Face,
-            Highway,
-            Location,
-            ModifyPerson,
-            Nose,
-            OptLockNotVersioned,
-            OptLockVersioned,
-            Person,
-            PersonEvent,
-            Pet,
-            PetType,
-            Plant,
-            PlantCategory,
-            Publication,
-            Task,
-            TestEntity
-    ]
+    private Set<Class> domainClasses = []
 
     /**
-     * Returns an unmodifiable view of the domain classes list.
-     * @return An unmodifiable list of domain classes
+     * Returns a defensive copy of the registered domain classes.
+     * Mutating this array will not affect the manager state.
      */
-    List<Class> getDomainClasses() {
-        Collections.unmodifiableList(domainClasses)
+    Class[] getDomainClasses() {
+        domainClasses as Class[]
     }
 
     @Deprecated
@@ -133,23 +76,12 @@ abstract class GrailsDataTckManager {
         System.setProperty(CURRENT_TEST_NAME, spec.getClass().simpleName - 
'Spec')
         session = createSession()
         DatastoreUtils.bindSession(session)
-        if (session?.datastore instanceof TransactionCapableDatastore) {
-            transactionManager = ((TransactionCapableDatastore) 
session.datastore).transactionManager
-            if (transactionManager != null) {
-                transactionStatus = transactionManager.getTransaction(new 
DefaultTransactionDefinition())
-            }
-        }
     }
 
     void cleanup() {
         System.clearProperty(CURRENT_TEST_NAME)
 
         try {
-            if (transactionManager != null && transactionStatus != null && 
!transactionStatus.completed) {
-                transactionManager.rollback(transactionStatus)
-            }
-            transactionStatus = null
-            transactionManager = null
             if (session) {
                 session.disconnect()
                 DatastoreUtils.unbindSession(session)
diff --git 
a/grails-datamapping-tck/src/main/groovy/org/apache/grails/data/testing/tck/tests/DomainEventsSpec.groovy
 
b/grails-datamapping-tck/src/main/groovy/org/apache/grails/data/testing/tck/tests/DomainEventsSpec.groovy
index af59d92b22..1c22893914 100644
--- 
a/grails-datamapping-tck/src/main/groovy/org/apache/grails/data/testing/tck/tests/DomainEventsSpec.groovy
+++ 
b/grails-datamapping-tck/src/main/groovy/org/apache/grails/data/testing/tck/tests/DomainEventsSpec.groovy
@@ -59,7 +59,6 @@ class DomainEventsSpec extends GrailsDataTckSpec {
         PersonEvent.get(p.id).name == 'Fred'
     }
 
-    @PendingFeature(reason = 'Hibernate identity generators insert immediately 
during persist(), before PreInsert veto can take effect')
     @Issue('GPMONGODB-262')
     void 'Test that returning false from beforeInsert evicts the event'() {
         when: 'false is returned from a beforeInsert event'
diff --git 
a/grails-datamapping-tck/src/main/groovy/org/apache/grails/data/testing/tck/tests/FirstAndLastMethodSpec.groovy
 
b/grails-datamapping-tck/src/main/groovy/org/apache/grails/data/testing/tck/tests/FirstAndLastMethodSpec.groovy
index 671bd13355..b27dfbd407 100644
--- 
a/grails-datamapping-tck/src/main/groovy/org/apache/grails/data/testing/tck/tests/FirstAndLastMethodSpec.groovy
+++ 
b/grails-datamapping-tck/src/main/groovy/org/apache/grails/data/testing/tck/tests/FirstAndLastMethodSpec.groovy
@@ -18,8 +18,6 @@
  */
 package org.apache.grails.data.testing.tck.tests
 
-import spock.lang.PendingFeatureIf
-
 import org.apache.grails.data.testing.tck.base.GrailsDataTckSpec
 import org.apache.grails.data.testing.tck.domains.PersonWithCompositeKey
 import org.apache.grails.data.testing.tck.domains.SimpleWidget
@@ -162,10 +160,6 @@ class FirstAndLastMethodSpec extends GrailsDataTckSpec {
         result?.name == 'three'
     }
 
-    @PendingFeatureIf(
-            value = { System.getProperty('hibernate5.gorm.suite') || 
System.getProperty('hibernate7.gorm.suite') },
-            reason = 'Was previously @Ignore'
-    )
     void 'Test first and last method with composite key'() {
         given:
         assert new PersonWithCompositeKey(firstName: 'Steve', lastName: 
'Harris', age: 56).save()


Reply via email to