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

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

commit 1d13ad208cb0b3c901cfb48dd4ed72687025d9c7
Author: Walter B Duque de Estrada <[email protected]>
AuthorDate: Fri Jan 16 10:39:02 2026 -0600

    update progress
---
 .../core/HIBERNATE7-UPGRADE-PROGRESS.md            |  20 ++-
 grails-data-hibernate7/core/build.gradle           |   1 +
 .../orm/hibernate/cfg/GrailsDomainBinder.java      |  77 +-------
 .../cfg/GrailsSequenceStyleGenerator.java          |  29 +++
 .../cfg/domainbinding/BasicValueIdCreator.java     |  68 +++++++
 .../cfg/domainbinding/SimpleIdBinder.java          |  65 +++++++
 .../domainbinding/BasicValueIdCreatorSpec.groovy   | 199 +++++++++++++++++++++
 .../cfg/domainbinding/SimpleIdBinderSpec.groovy    | 114 ++++++++++++
 8 files changed, 499 insertions(+), 74 deletions(-)

diff --git a/grails-data-hibernate7/core/HIBERNATE7-UPGRADE-PROGRESS.md 
b/grails-data-hibernate7/core/HIBERNATE7-UPGRADE-PROGRESS.md
index 501a9db689..3186baf474 100644
--- a/grails-data-hibernate7/core/HIBERNATE7-UPGRADE-PROGRESS.md
+++ b/grails-data-hibernate7/core/HIBERNATE7-UPGRADE-PROGRESS.md
@@ -49,10 +49,26 @@ This document summarizes the approaches taken, challenges 
encountered, and futur
 - **Reasoning:** Hibernate 7's default naming strategies preserve dots in 
logical names (e.g., from FQCNs), which leads to invalid SQL in databases like 
H2. GORM expects underscores for compatibility and valid SQL.
 - **Result:** Resolved `JdbcSQLSyntaxErrorException` in tests like 
`CascadeBehaviorPersisterSpec`, where join table columns now use valid 
underscore-delimited names instead of dotted class names.
 
+### 8. Refactoring of `AbstractGrailsDomainBinder`
+- **Approach:** Merged `AbstractGrailsDomainBinder` into `GrailsDomainBinder` 
to simplify the class hierarchy and remove the abstract base class.
+- **Result:** `AbstractGrailsDomainBinder` has been removed and its 
functionality (mapping cache management) is now part of `GrailsDomainBinder`.
+
+### 9. Test Fixes for Sealed Classes
+- **Issue:** Tests were failing with "Sealed class ... cannot be mocked" for 
Hibernate classes like `Column`, `Table`, and `UniqueKey`.
+- **Approach:** Refactored tests (`ColumnConfigToColumnBinderSpec`, 
`StringColumnConstraintsBinderSpec`, `IndexBinderSpec`, 
`UniqueNameGeneratorSpec`) to instantiate these classes instead of mocking them.
+- **Result:** Resolved mocking errors for sealed classes.
+
+### 10. Fixes for `BasicValueIdCreatorSpec` and `ManyToOneBinderSpec`
+- **Issue:** `BasicValueIdCreatorSpec` failed with NPE in `NativeGenerator`. 
`ManyToOneBinderSpec` failed with `MissingMethodException`.
+- **Approach:**
+    - In `BasicValueIdCreatorSpec`, mocked `Database`, `Dialect`, and 
`GenerationType` to satisfy `NativeGenerator` initialization.
+    - In `ManyToOneBinderSpec`, replaced `setCompositeIdentifier` with 
`setIdentity` and mocked `PropertyConfig` to handle `setUniqueWithinGroup`.
+- **Result:** Resolved these specific test failures.
+
 ## Challenges & Failures
 
 ### 1. Proxy Initialization Behavior
-- **Issue:** In `Hibernate6GroovyProxySpec`, `Location.proxy(id)` returns an 
object that is already initialized (`Hibernate.isInitialized(location) == 
true`), even after clearing the session.
+- **Issue:** In `Hibernate7GroovyProxySpec`, `Location.proxy(id)` returns an 
object that is already initialized (`Hibernate.isInitialized(location) == 
true`), even after clearing the session.
 - **Attempts:** Tried `session.getReference()`, 
`session.byId().getReference()`, and using fresh sessions.
 - **Status:** Ongoing investigation. Debugging indicates that Hibernate 7's 
bytecode enhancement or session management might be reporting Groovy proxies as 
initialized even when they haven't fetched their target.
 
@@ -85,7 +101,7 @@ Unit tests should be created for each new binder class 
(e.g., `CollectionBinderS
 
 ## Future Steps
 
-1.  **Resolve Proxy Initialization:** Determine why proxies are returning as 
initialized in `Hibernate6GroovyProxySpec`. Investigate if Hibernate 7's 
bytecode enhancement or ByteBuddy factory settings are interfering.
+1.  **Resolve Proxy Initialization:** Determine why proxies are returning as 
initialized in `Hibernate7GroovyProxySpec`. Investigate if Hibernate 7's 
bytecode enhancement or ByteBuddy factory settings are interfering.
 2.  **Fix DDL Generation:** Investigate why FQCNs are leaking into DDL column 
definitions. This likely requires further changes in `ColumnNameFetcher` or the 
mapping binders to ensure dots are replaced by underscores globally for 
generated columns.
 3. Continue TCK Failure Audit:
     - `HibernateGormDatastoreSpec` (Base class, not directly runnable - 
Pending)
diff --git a/grails-data-hibernate7/core/build.gradle 
b/grails-data-hibernate7/core/build.gradle
index 1b63057321..840f888c28 100644
--- a/grails-data-hibernate7/core/build.gradle
+++ b/grails-data-hibernate7/core/build.gradle
@@ -99,6 +99,7 @@ dependencies {
     testImplementation 'org.apache.groovy:groovy-json'
     testImplementation 'org.hibernate.orm:hibernate-jcache'
     testImplementation 'org.spockframework:spock-core'
+    testImplementation "org.hibernate.orm:hibernate-core:$hibernate7Version"
 
     // groovy proxy fixes bytebuddy to be a bit smarter when it comes to 
groovy metaClass
     testImplementation 
"org.yakworks:hibernate-groovy-proxy:$yakworksHibernateGroovyProxyVersion", {
diff --git 
a/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/cfg/GrailsDomainBinder.java
 
b/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/cfg/GrailsDomainBinder.java
index 4a36a3e597..78c584b852 100644
--- 
a/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/cfg/GrailsDomainBinder.java
+++ 
b/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/cfg/GrailsDomainBinder.java
@@ -36,6 +36,7 @@ import 
org.grails.orm.hibernate.cfg.domainbinding.PersistentPropertyToPropertyCo
 import org.grails.orm.hibernate.cfg.domainbinding.SimpleValueColumnBinder;
 import org.grails.orm.hibernate.cfg.domainbinding.TypeNameProvider;
 import org.grails.orm.hibernate.cfg.domainbinding.*;
+
 import org.hibernate.FetchMode;
 import org.hibernate.MappingException;
 import org.hibernate.boot.ResourceStreamLocator;
@@ -94,8 +95,8 @@ import java.util.HashSet;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
-import java.util.Optional;
 import java.util.Set;
+import java.util.Optional;
 import java.util.SortedSet;
 import java.util.StringTokenizer;
 
@@ -118,7 +119,7 @@ public class GrailsDomainBinder
     public static final String FOREIGN_KEY_SUFFIX = "_id";
     protected static final Map<Class<?>, Mapping> MAPPING_CACHE = new 
HashMap<>();
     private static final String STRING_TYPE = "string";
-    private static final String EMPTY_PATH = "";
+    public static final String EMPTY_PATH = "";
     public static final char UNDERSCORE = '_';
     public static final String BACKTICK = "`";
 
@@ -2009,77 +2010,9 @@ public class GrailsDomainBinder
     @SuppressWarnings("unchecked")
     private void bindSimpleId(PersistentProperty identifier, RootClass entity,
                                 InFlightMetadataCollector mappings, Identity 
mappedId, String sessionFactoryBeanName) {
+        SimpleIdBinder simpleIdBinder = new 
SimpleIdBinder(metadataBuildingContext,namingStrategy);
+        simpleIdBinder.bindSimpleId(identifier, entity, mappedId);
 
-        boolean useSequence = new 
HibernateEntityWrapper().getMappedForm(identifier.getOwner()).isTablePerConcreteClass();
-        // create the id value
-        BasicValue id = new BasicValue(metadataBuildingContext, 
entity.getTable());
-
-        String generator;
-        if (mappedId == null) {
-            generator = useSequence ? "sequence-identity" : "native";
-        } else {
-            generator = mappedId.getGenerator();
-            if ("native".equals(generator) && useSequence) {
-                generator = "sequence-identity";
-            }
-        }
-
-        switch (generator) {
-            case "identity" -> id.setCustomIdGeneratorCreator(context -> {
-                // Force IdentityGenerator for databases like MySQL/H2
-                var gen = new org.hibernate.id.IdentityGenerator();
-                
context.getProperty().getValue().getColumns().get(0).setIdentity(true);
-                return gen;
-            });
-
-            case "sequence", "sequence-identity" -> 
id.setCustomIdGeneratorCreator(context -> {
-                // Use the modern SequenceStyleGenerator
-                return new org.hibernate.id.enhanced.SequenceStyleGenerator();
-            });
-
-            case "increment" -> id.setCustomIdGeneratorCreator(context -> {
-                return new org.hibernate.id.IncrementGenerator();
-            });
-
-            case "uuid", "uuid2" -> id.setCustomIdGeneratorCreator(context -> {
-                return new 
org.hibernate.id.uuid.UuidGenerator(context.getType().getReturnedClass());
-            });
-
-            case "assigned" -> id.setCustomIdGeneratorCreator(context -> {
-                return new org.hibernate.id.Assigned();
-            });
-
-            case "table", "enhanced-table" -> 
id.setCustomIdGeneratorCreator(context -> {
-                return new org.hibernate.id.enhanced.TableGenerator();
-            });
-
-            case "hilo" -> id.setCustomIdGeneratorCreator(context -> {
-                // Note: Legacy Hilo is often replaced by 
SequenceStyleGenerator with optimizer
-                return new org.hibernate.id.enhanced.SequenceStyleGenerator();
-            });
-
-            default -> 
id.setCustomIdGeneratorCreator(GrailsNativeGenerator::new);
-        }
-
-        Property idProperty  = new Property();
-        idProperty.setName(identifier.getName());
-        idProperty.setValue(id);
-        entity.setDeclaredIdentifierProperty(idProperty);
-        entity.setIdentifier(id);
-        // set type
-        new SimpleValueBinder(namingStrategy).bindSimpleValue(identifier, 
null, id, EMPTY_PATH);
-
-        // create property
-        Property prop = new Property();
-        prop.setValue(id);
-
-        // bind property
-        new PropertyBinder().bindProperty(identifier, prop);
-        // set identifier property
-        entity.setIdentifierProperty(prop);
-
-        Table table = id.getTable();
-        table.setPrimaryKey(new PrimaryKey(table));
     }
 
 
diff --git 
a/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/cfg/GrailsSequenceStyleGenerator.java
 
b/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/cfg/GrailsSequenceStyleGenerator.java
new file mode 100644
index 0000000000..3d8938cf47
--- /dev/null
+++ 
b/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/cfg/GrailsSequenceStyleGenerator.java
@@ -0,0 +1,29 @@
+package org.grails.orm.hibernate.cfg;
+
+import org.hibernate.MappingException;
+import org.hibernate.boot.model.relational.Database;
+import org.hibernate.dialect.Dialect;
+import org.hibernate.engine.jdbc.env.spi.JdbcEnvironment;
+import org.hibernate.generator.GeneratorCreationContext;
+import org.hibernate.id.enhanced.SequenceStyleGenerator;
+import org.hibernate.service.ServiceRegistry;
+import org.hibernate.type.Type;
+
+import java.util.Map;
+import java.util.Properties;
+import java.util.Set;
+
+public class GrailsSequenceStyleGenerator extends SequenceStyleGenerator {
+
+    public GrailsSequenceStyleGenerator(GeneratorCreationContext context, 
Identity mappedId) {
+        // Call super's no-arg constructor first
+        super();
+        Properties generatorProps = new Properties();
+        if (mappedId != null && mappedId.getParams() != null) {
+            for (Map.Entry entry : (Set<Map.Entry>) 
mappedId.getParams().entrySet()) {
+                generatorProps.setProperty(entry.getKey().toString(), 
entry.getValue().toString());
+            }
+        }
+        super.configure(context.getType(), generatorProps, 
context.getServiceRegistry());
+    }
+}
diff --git 
a/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/cfg/domainbinding/BasicValueIdCreator.java
 
b/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/cfg/domainbinding/BasicValueIdCreator.java
new file mode 100644
index 0000000000..1915943aba
--- /dev/null
+++ 
b/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/cfg/domainbinding/BasicValueIdCreator.java
@@ -0,0 +1,68 @@
+package org.grails.orm.hibernate.cfg.domainbinding;
+
+import org.hibernate.boot.spi.MetadataBuildingContext;
+import org.hibernate.mapping.BasicValue;
+import org.hibernate.mapping.RootClass;
+
+import org.grails.orm.hibernate.cfg.GrailsSequenceStyleGenerator;
+import org.grails.orm.hibernate.cfg.Identity;
+
+public class BasicValueIdCreator {
+
+    private final  MetadataBuildingContext metadataBuildingContext;
+
+    public BasicValueIdCreator(MetadataBuildingContext metadataBuildingContext 
) {
+        this.metadataBuildingContext = metadataBuildingContext;
+    }
+
+    public BasicValue getBasicValueId(RootClass entity, Identity mappedId, 
boolean useSequence) {
+        BasicValue id = new BasicValue(metadataBuildingContext, 
entity.getTable());
+
+        String generator;
+        if (mappedId == null) {
+            generator = useSequence ? "sequence-identity" : "native";
+        } else {
+            generator = mappedId.getGenerator();
+            if ("native".equals(generator) && useSequence) {
+                generator = "sequence-identity";
+            }
+        }
+
+        switch (generator) {
+            case "identity" -> id.setCustomIdGeneratorCreator(context -> {
+                // Force IdentityGenerator for databases like MySQL/H2
+                var gen = new org.hibernate.id.IdentityGenerator();
+                
context.getProperty().getValue().getColumns().get(0).setIdentity(true);
+                return gen;
+            });
+
+            case "sequence", "sequence-identity" -> 
id.setCustomIdGeneratorCreator(context -> {
+                return new GrailsSequenceStyleGenerator(context,mappedId);
+            });
+
+            case "increment" -> id.setCustomIdGeneratorCreator(context -> {
+                return new org.hibernate.id.IncrementGenerator();
+            });
+
+            case "uuid", "uuid2" -> id.setCustomIdGeneratorCreator(context -> {
+                return new 
org.hibernate.id.uuid.UuidGenerator(context.getType().getReturnedClass());
+            });
+
+            case "assigned" -> id.setCustomIdGeneratorCreator(context -> {
+                return new org.hibernate.id.Assigned();
+            });
+
+            case "table", "enhanced-table" -> 
id.setCustomIdGeneratorCreator(context -> {
+                return new org.hibernate.id.enhanced.TableGenerator();
+            });
+
+            case "hilo" -> id.setCustomIdGeneratorCreator(context -> {
+                // Note: Legacy Hilo is often replaced by 
SequenceStyleGenerator with optimizer
+                return new org.hibernate.id.enhanced.SequenceStyleGenerator();
+            });
+
+            default -> 
id.setCustomIdGeneratorCreator(GrailsNativeGenerator::new);
+        }
+        return id;
+    }
+}
diff --git 
a/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/cfg/domainbinding/SimpleIdBinder.java
 
b/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/cfg/domainbinding/SimpleIdBinder.java
new file mode 100644
index 0000000000..e48b5251d2
--- /dev/null
+++ 
b/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/cfg/domainbinding/SimpleIdBinder.java
@@ -0,0 +1,65 @@
+package org.grails.orm.hibernate.cfg.domainbinding;
+
+import org.hibernate.boot.spi.MetadataBuildingContext;
+import org.hibernate.mapping.BasicValue;
+import org.hibernate.mapping.PrimaryKey;
+import org.hibernate.mapping.Property;
+import org.hibernate.mapping.RootClass;
+import org.hibernate.mapping.Table;
+
+import org.grails.datastore.mapping.model.PersistentProperty;
+import org.grails.orm.hibernate.cfg.Identity;
+import org.grails.orm.hibernate.cfg.PersistentEntityNamingStrategy;
+
+import static org.grails.orm.hibernate.cfg.GrailsDomainBinder.EMPTY_PATH;
+
+public class SimpleIdBinder {
+
+    private final BasicValueIdCreator basicValueIdCreator;
+    private final HibernateEntityWrapper hibernateEntityWrapper;
+    private final SimpleValueBinder simpleValueBinder;
+    private final PropertyBinder propertyBinder;
+
+    public SimpleIdBinder(MetadataBuildingContext metadataBuildingContext, 
PersistentEntityNamingStrategy namingStrategy)  {
+        this.basicValueIdCreator = new 
BasicValueIdCreator(metadataBuildingContext);
+        this.hibernateEntityWrapper = new HibernateEntityWrapper();
+        this.simpleValueBinder =new SimpleValueBinder(namingStrategy);
+        this.propertyBinder = new PropertyBinder();
+    }
+
+    protected SimpleIdBinder(BasicValueIdCreator basicValueIdCreate, 
HibernateEntityWrapper hibernateEntityWrapper, SimpleValueBinder 
simpleValueBinder, PropertyBinder propertyBinder) {
+        this.basicValueIdCreator = basicValueIdCreate;
+        this.hibernateEntityWrapper = hibernateEntityWrapper;
+        this.simpleValueBinder = simpleValueBinder;
+        this.propertyBinder = propertyBinder;
+    }
+
+
+    public void bindSimpleId(PersistentProperty identifier, RootClass entity, 
Identity mappedId) {
+
+        boolean useSequence = 
hibernateEntityWrapper.getMappedForm(identifier.getOwner()).isTablePerConcreteClass();
+        // create the id value
+
+        BasicValue id = basicValueIdCreator.getBasicValueId(entity, mappedId, 
useSequence);
+
+        Property idProperty  = new Property();
+        idProperty.setName(identifier.getName());
+        idProperty.setValue(id);
+        entity.setDeclaredIdentifierProperty(idProperty);
+        entity.setIdentifier(id);
+        // set type
+        simpleValueBinder.bindSimpleValue(identifier, null, id, EMPTY_PATH);
+
+        // create property
+        Property prop = new Property();
+        prop.setValue(id);
+
+        // bind property
+        propertyBinder.bindProperty(identifier, prop);
+        // set identifier property
+        entity.setIdentifierProperty(prop);
+
+        Table table = id.getTable();
+        table.setPrimaryKey(new PrimaryKey(table));
+    }
+}
diff --git 
a/grails-data-hibernate7/core/src/test/groovy/org/grails/orm/hibernate/cfg/domainbinding/BasicValueIdCreatorSpec.groovy
 
b/grails-data-hibernate7/core/src/test/groovy/org/grails/orm/hibernate/cfg/domainbinding/BasicValueIdCreatorSpec.groovy
new file mode 100644
index 0000000000..5b47980b64
--- /dev/null
+++ 
b/grails-data-hibernate7/core/src/test/groovy/org/grails/orm/hibernate/cfg/domainbinding/BasicValueIdCreatorSpec.groovy
@@ -0,0 +1,199 @@
+package org.grails.orm.hibernate.cfg.domainbinding
+
+import grails.gorm.specs.HibernateGormDatastoreSpec
+import jakarta.persistence.GenerationType
+import org.grails.orm.hibernate.cfg.GrailsSequenceStyleGenerator
+import org.grails.orm.hibernate.cfg.Identity
+import org.hibernate.boot.model.naming.Identifier
+import org.hibernate.boot.model.relational.Database
+import org.hibernate.boot.spi.MetadataBuildingContext
+import org.hibernate.dialect.Dialect
+import org.hibernate.dialect.sequence.SequenceSupport
+import org.hibernate.engine.config.spi.ConfigurationService
+import org.hibernate.engine.jdbc.env.spi.IdentifierHelper
+import org.hibernate.engine.jdbc.env.spi.JdbcEnvironment
+import org.hibernate.generator.Generator
+import org.hibernate.generator.GeneratorCreationContext
+import org.hibernate.id.Assigned
+import org.hibernate.id.IdentityGenerator
+import org.hibernate.id.IncrementGenerator
+import org.hibernate.id.enhanced.SequenceStyleGenerator
+import org.hibernate.id.enhanced.TableGenerator
+import org.hibernate.id.uuid.UuidGenerator
+import org.hibernate.mapping.BasicValue
+import org.hibernate.mapping.Column
+import org.hibernate.mapping.Property
+import org.hibernate.mapping.RootClass
+import org.hibernate.mapping.Table
+import org.hibernate.mapping.Value
+import org.hibernate.service.ServiceRegistry
+import org.hibernate.type.BasicType
+import spock.lang.Unroll
+
+class BasicValueIdCreatorSpec extends HibernateGormDatastoreSpec {
+
+    MetadataBuildingContext metadataBuildingContext
+    BasicValueIdCreator creator
+    RootClass entity
+    Table table
+
+    def setup() {
+        metadataBuildingContext = 
getGrailsDomainBinder().getMetadataBuildingContext()
+        creator = new BasicValueIdCreator(metadataBuildingContext)
+        entity = new RootClass(metadataBuildingContext)
+        table = new Table("test_table")
+        entity.setTable(table)
+    }
+
+    @Unroll
+    def "should create BasicValue with correct generator for #generatorName 
(useSequence: #useSequence)"() {
+        given:
+        Identity mappedId = new Identity()
+        mappedId.setGenerator(generatorName)
+        def property = createDummyProperty()
+
+        when:
+        BasicValue id = creator.getBasicValueId(entity, mappedId, useSequence)
+        def generatorCreator = id.getCustomIdGeneratorCreator()
+        Generator generator = 
generatorCreator.createGenerator(createContext(id, property))
+
+        then:
+        expectedClass.isInstance(generator)
+
+        where:
+        generatorName       | useSequence | expectedClass
+        "identity"          | false       | IdentityGenerator
+        "sequence"          | true        | GrailsSequenceStyleGenerator
+        "sequence-identity" | true        | GrailsSequenceStyleGenerator
+        "increment"         | false       | IncrementGenerator
+        "uuid"              | false       | UuidGenerator
+        "uuid2"             | false       | UuidGenerator
+        "assigned"          | false       | Assigned
+        "table"             | false       | TableGenerator
+        "enhanced-table"    | false       | TableGenerator
+        "hilo"              | false       | SequenceStyleGenerator
+    }
+
+    def "should default to native generator when mappedId is null"() {
+        when:
+        BasicValue id = creator.getBasicValueId(entity, null, false)
+        def generatorCreator = id.getCustomIdGeneratorCreator()
+        Generator generator = 
generatorCreator.createGenerator(createContext(id))
+
+        then:
+        generator instanceof GrailsNativeGenerator
+    }
+
+    def "should default to sequence-identity when mappedId is null and 
useSequence is true"() {
+        when:
+        BasicValue id = creator.getBasicValueId(entity, null, true)
+        def generatorCreator = id.getCustomIdGeneratorCreator()
+        Generator generator = 
generatorCreator.createGenerator(createContext(id))
+
+        then:
+        generator instanceof GrailsSequenceStyleGenerator
+    }
+
+    def "should use sequence-identity when generator is native and useSequence 
is true"() {
+        given:
+        Identity mappedId = new Identity()
+        mappedId.setGenerator("native")
+
+        when:
+        BasicValue id = creator.getBasicValueId(entity, mappedId, true)
+        def generatorCreator = id.getCustomIdGeneratorCreator()
+        Generator generator = 
generatorCreator.createGenerator(createContext(id))
+
+        then:
+        generator instanceof GrailsSequenceStyleGenerator
+    }
+
+    def "should configure identity column for identity generator"() {
+        given:
+        Identity mappedId = new Identity()
+        mappedId.setGenerator("identity")
+        // We need a real column structure for IdentityGenerator to work with
+        def column = new Column("id")
+        
+        // Mocking the context to simulate what Hibernate passes
+        def property = Mock(Property)
+        def value = Mock(Value) // We can mock Value interface
+        value.getColumns() >> [column]
+        property.getValue() >> value
+        
+        when:
+        BasicValue id = creator.getBasicValueId(entity, mappedId, false)
+        def generatorCreator = id.getCustomIdGeneratorCreator()
+        def context = createContext(id, property)
+        
+        generatorCreator.createGenerator(context)
+
+        then:
+        column.isIdentity()
+    }
+
+    def "should pass generator properties to sequence generator"() {
+        given:
+        Identity mappedId = new Identity()
+        mappedId.setGenerator("sequence")
+        mappedId.setParams([sequence_name: "my_seq"])
+
+        when:
+        BasicValue id = creator.getBasicValueId(entity, mappedId, true)
+        def generatorCreator = id.getCustomIdGeneratorCreator()
+        GrailsSequenceStyleGenerator generator = 
(GrailsSequenceStyleGenerator) 
generatorCreator.createGenerator(createContext(id))
+
+        then:
+        
generator.getDatabaseStructure().getPhysicalName().getObjectName().getText() == 
"my_seq"
+    }
+
+    private Property createDummyProperty() {
+        def column = new Column("id")
+        def property = Mock(Property)
+        def value = Mock(Value)
+        value.getColumns() >> [column]
+        property.getValue() >> value
+        return property
+    }
+
+    private GeneratorCreationContext createContext(BasicValue id, Property 
property = null) {
+        def context = Mock(GeneratorCreationContext)
+        def type = Mock(BasicType)
+        def database = Mock(Database)
+        def dialect = Mock(Dialect)
+        def serviceRegistry = Mock(ServiceRegistry)
+        def jdbcEnvironment = Mock(JdbcEnvironment)
+        def identifierHelper = Mock(IdentifierHelper)
+        def sequenceSupport = Mock(SequenceSupport)
+        def configurationService = Mock(ConfigurationService)
+
+        type.getReturnedClass() >> String.class
+        context.getType() >> type
+        
+        // Mocking for NativeGenerator
+        context.getDatabase() >> database
+        database.getDialect() >> dialect
+        dialect.getNativeValueGenerationStrategy() >> GenerationType.SEQUENCE
+        dialect.getSequenceSupport() >> sequenceSupport
+        sequenceSupport.supportsSequences() >> true
+
+        // Mocking for SequenceStyleGenerator
+        context.getServiceRegistry() >> serviceRegistry
+        serviceRegistry.requireService(JdbcEnvironment.class) >> 
jdbcEnvironment
+        serviceRegistry.requireService(ConfigurationService.class) >> 
configurationService
+        jdbcEnvironment.getDialect() >> dialect
+        jdbcEnvironment.getIdentifierHelper() >> identifierHelper
+        identifierHelper.toIdentifier(_, _) >> { String text, boolean quoted 
-> 
+            return text == null ? null : new Identifier(text, quoted)
+        }
+        identifierHelper.toIdentifier(_) >> { String text -> 
+            return text == null ? null : new Identifier(text, false)
+        }
+
+        if (property != null) {
+            context.getProperty() >> property
+        }
+
+        return context
+    }
+}
diff --git 
a/grails-data-hibernate7/core/src/test/groovy/org/grails/orm/hibernate/cfg/domainbinding/SimpleIdBinderSpec.groovy
 
b/grails-data-hibernate7/core/src/test/groovy/org/grails/orm/hibernate/cfg/domainbinding/SimpleIdBinderSpec.groovy
new file mode 100644
index 0000000000..b9029822ea
--- /dev/null
+++ 
b/grails-data-hibernate7/core/src/test/groovy/org/grails/orm/hibernate/cfg/domainbinding/SimpleIdBinderSpec.groovy
@@ -0,0 +1,114 @@
+package org.grails.orm.hibernate.cfg.domainbinding
+
+import grails.gorm.annotation.Entity
+import grails.gorm.specs.HibernateGormDatastoreSpec
+import grails.persistence.Entity
+import org.grails.orm.hibernate.cfg.Identity
+import org.grails.orm.hibernate.cfg.PersistentEntityNamingStrategy
+import org.hibernate.boot.spi.MetadataBuildingContext
+import org.hibernate.mapping.BasicValue
+import org.hibernate.mapping.RootClass
+import org.hibernate.mapping.Table
+import spock.lang.Issue
+
+class SimpleIdBinderSpec extends HibernateGormDatastoreSpec {
+
+    def metadataBuildingContext
+    def namingStrategy
+    def hibernateEntityWrapper
+    def simpleValueBinder
+    def propertyBinder
+    def basicValueIdCreator
+
+    def simpleIdBinder // Subject under test
+
+    def setup() {
+        metadataBuildingContext = 
getGrailsDomainBinder().getMetadataBuildingContext()
+        namingStrategy = Mock(PersistentEntityNamingStrategy)
+        hibernateEntityWrapper = Mock(HibernateEntityWrapper)
+        simpleValueBinder = Mock(SimpleValueBinder)
+        propertyBinder = Mock(PropertyBinder)
+        // Use real BasicValueIdCreator instead of Mock to avoid issues
+        basicValueIdCreator = new BasicValueIdCreator(metadataBuildingContext)
+
+        simpleIdBinder = new SimpleIdBinder(basicValueIdCreator, 
hibernateEntityWrapper, simpleValueBinder, propertyBinder)
+    }
+
+
+    def "test bindSimpleId method with identity generator"() {
+        given:
+        def testEntity = createPersistentEntity(TestEntityId)
+        assert testEntity != null
+        def rootClass = new RootClass(metadataBuildingContext)
+        def table = new Table("TEST_TABLE")
+        rootClass.setTable(table)
+
+        def mappedId = new Identity(generator: "identity")
+        def testProperty = testEntity.getIdentity()
+
+        // Stubbing interactions
+        hibernateEntityWrapper.getMappedForm(_) >> 
Mock(org.grails.orm.hibernate.cfg.Mapping) {
+            isTablePerConcreteClass() >> false
+        }
+
+        when:
+        simpleIdBinder.bindSimpleId(testProperty, rootClass, mappedId)
+
+        then:
+        1 * simpleValueBinder.bindSimpleValue(testProperty, null, _, '')
+        1 * propertyBinder.bindProperty(testProperty, _)
+        
+        rootClass.identifier instanceof BasicValue
+        rootClass.declaredIdentifierProperty != null
+        rootClass.identifierProperty != null
+        rootClass.table.primaryKey != null
+    }
+
+    def "test bindSimpleId method with sequence generator"() {
+        given:
+        def testEntity = createPersistentEntity(TestEntitySeq)
+        assert testEntity != null
+        def rootClass = new RootClass(metadataBuildingContext)
+        def table = new Table("TEST_TABLE")
+        rootClass.setTable(table)
+
+        def mappedId = new Identity(generator: "sequence", params: [sequence: 
"SEQ_TEST"])
+        def testProperty = testEntity.getIdentity()
+
+        // Stubbing interactions
+        hibernateEntityWrapper.getMappedForm(_) >> 
Mock(org.grails.orm.hibernate.cfg.Mapping) {
+            isTablePerConcreteClass() >> true
+        }
+
+        when:
+        simpleIdBinder.bindSimpleId(testProperty, rootClass, mappedId)
+
+        then:
+        1 * simpleValueBinder.bindSimpleValue(testProperty, null, _, '')
+        1 * propertyBinder.bindProperty(testProperty, _)
+        
+        rootClass.identifier instanceof BasicValue
+        rootClass.declaredIdentifierProperty != null
+        rootClass.identifierProperty != null
+        rootClass.table.primaryKey != null
+    }
+}
+
+// Helper domain classes
+@Entity
+class TestEntityId {
+    Long id
+    String name
+    static mapping = {
+        id generator: 'identity'
+    }
+}
+
+@Entity
+class TestEntitySeq {
+    Long id
+    String name
+    static mapping = {
+        id generator: 'sequence', params: [sequence: 'SEQ_TEST']
+    }
+}

Reply via email to