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 bd79b537f70a0a65cd80b6ddbabc2c0aecce0184
Author: Walter Duque de Estrada <[email protected]>
AuthorDate: Mon Feb 16 21:15:37 2026 -0600

    Refactor composite identity property resolution
    
    - Encapsulate composite identifier property resolution within 
CompositeIdentity.
    - Move property validation and mapping logic from CompositeIdBinder to 
CompositeIdentity.getHibernateProperties.
    - Update CompositeIdBinder to delegate property retrieval to the new method.
---
 .../orm/hibernate/cfg/CompositeIdentity.groovy     | 21 +++++++
 .../domainbinding/binder/CompositeIdBinder.java    | 21 +------
 .../orm/hibernate/cfg/CompositeIdentitySpec.groovy | 69 ++++++++++++++++++++++
 .../cfg/domainbinding/CollectionBinderSpec.groovy  |  2 +-
 .../CollectionSecondPassBinderSpec.groovy          |  2 +-
 .../cfg/domainbinding/CompositeIdBinderSpec.groovy | 16 ++---
 .../domainbinding/ListSecondPassBinderSpec.groovy  |  2 +-
 .../domainbinding/MapSecondPassBinderSpec.groovy   |  2 +-
 8 files changed, 105 insertions(+), 30 deletions(-)

diff --git 
a/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/cfg/CompositeIdentity.groovy
 
b/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/cfg/CompositeIdentity.groovy
index b39454ddc3..6a9dd5ccd7 100644
--- 
a/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/cfg/CompositeIdentity.groovy
+++ 
b/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/cfg/CompositeIdentity.groovy
@@ -21,6 +21,7 @@ import groovy.transform.builder.Builder
 import groovy.transform.builder.SimpleStrategy
 import org.grails.datastore.mapping.config.Property
 import org.grails.orm.hibernate.cfg.domainbinding.hibernate.HibernateIdentity
+import org.hibernate.MappingException
 
 /**
  * Represents a composite identity, equivalent to Hibernate <composite-id> 
mapping.
@@ -57,4 +58,24 @@ class CompositeIdentity extends Property implements 
HibernateIdentity {
         naturalIdDef.call()
         return this
     }
+
+    /**
+     * @param domainClass The domain class
+     * @return The hibernate properties for the composite identity
+     */
+    GrailsHibernatePersistentProperty[] 
getHibernateProperties(GrailsHibernatePersistentEntity domainClass) {
+        GrailsHibernatePersistentProperty[] composite = propertyNames ?
+                propertyNames.collect { domainClass.getPropertyByName(it) as 
GrailsHibernatePersistentProperty } as GrailsHibernatePersistentProperty[] :
+                domainClass.compositeIdentity
+
+        if (!composite) {
+            throw new MappingException("No composite identifier properties 
found for class [${domainClass.name}]")
+        }
+
+        if (composite.any { it == null }) {
+            throw new MappingException("Property referenced in composite-id 
mapping of class [${domainClass.name}] is not a valid property!")
+        }
+
+        composite
+    }
 }
diff --git 
a/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/cfg/domainbinding/binder/CompositeIdBinder.java
 
b/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/cfg/domainbinding/binder/CompositeIdBinder.java
index d1fd576507..469e5be6ad 100644
--- 
a/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/cfg/domainbinding/binder/CompositeIdBinder.java
+++ 
b/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/cfg/domainbinding/binder/CompositeIdBinder.java
@@ -43,28 +43,13 @@ public class CompositeIdBinder {
 
         id.setRoleName(path);
 
-        GrailsHibernatePersistentProperty[] composite;
-        if (compositeIdentity != null && compositeIdentity.getPropertyNames() 
!= null) {
-            String[] propertyNames = compositeIdentity.getPropertyNames();
-            composite = new 
GrailsHibernatePersistentProperty[propertyNames.length];
-            for (int i = 0; i < propertyNames.length; i++) {
-                composite[i] = (GrailsHibernatePersistentProperty) 
domainClass.getPropertyByName(propertyNames[i]);
-            }
-        } else {
-            composite = domainClass.getCompositeIdentity();
-        }
-
-        if (composite == null) {
-            throw new MappingException("No composite identifier properties 
found for class [" + domainClass.getName() + "]");
+        if (compositeIdentity == null) {
+            compositeIdentity = new CompositeIdentity();
         }
+        GrailsHibernatePersistentProperty[] composite = 
compositeIdentity.getHibernateProperties(domainClass);
 
         GrailsHibernatePersistentProperty identifierProp = 
domainClass.getIdentity();
         for (GrailsHibernatePersistentProperty property : composite) {
-            if (property == null) {
-                throw new MappingException("Property referenced in 
composite-id mapping of class [" + domainClass.getName() +
-                        "] is not a valid property!");
-            }
-
            var value = grailsPropertyBinder.bindProperty(root, 
root.getTable(), "", identifierProp, property, mappings);
            componentUpdater.updateComponent(id, identifierProp, property, 
value);
         }
diff --git 
a/grails-data-hibernate7/core/src/test/groovy/org/grails/orm/hibernate/cfg/CompositeIdentitySpec.groovy
 
b/grails-data-hibernate7/core/src/test/groovy/org/grails/orm/hibernate/cfg/CompositeIdentitySpec.groovy
new file mode 100644
index 0000000000..043adca121
--- /dev/null
+++ 
b/grails-data-hibernate7/core/src/test/groovy/org/grails/orm/hibernate/cfg/CompositeIdentitySpec.groovy
@@ -0,0 +1,69 @@
+package org.grails.orm.hibernate.cfg
+
+import org.hibernate.MappingException
+import spock.lang.Specification
+import org.grails.orm.hibernate.cfg.GrailsHibernatePersistentEntity
+import org.grails.orm.hibernate.cfg.GrailsHibernatePersistentProperty
+
+class CompositeIdentitySpec extends Specification {
+
+    def "test getHibernateProperties with property names"() {
+        given:
+        def domainClass = Mock(GrailsHibernatePersistentEntity)
+        def prop1 = Mock(GrailsHibernatePersistentProperty)
+        def prop2 = Mock(GrailsHibernatePersistentProperty)
+        def compositeIdentity = new CompositeIdentity(propertyNames: ['prop1', 
'prop2'] as String[])
+
+        when:
+        def properties = compositeIdentity.getHibernateProperties(domainClass)
+
+        then:
+        1 * domainClass.getPropertyByName("prop1") >> prop1
+        1 * domainClass.getPropertyByName("prop2") >> prop2
+        properties.length == 2
+        properties[0] == prop1
+        properties[1] == prop2
+    }
+
+    def "test getHibernateProperties with fallback to domain class"() {
+        given:
+        def domainClass = Mock(GrailsHibernatePersistentEntity)
+        def prop1 = Mock(GrailsHibernatePersistentProperty)
+        def compositeIdentity = new CompositeIdentity()
+
+        when:
+        def properties = compositeIdentity.getHibernateProperties(domainClass)
+
+        then:
+        1 * domainClass.getCompositeIdentity() >> ([prop1] as 
GrailsHibernatePersistentProperty[])
+        0 * domainClass.getPropertyByName(_)
+        properties.length == 1
+        properties[0] == prop1
+    }
+
+    def "test getHibernateProperties throws exception if no properties 
found"() {
+        given:
+        def domainClass = Mock(GrailsHibernatePersistentEntity)
+        def compositeIdentity = new CompositeIdentity()
+
+        when:
+        compositeIdentity.getHibernateProperties(domainClass)
+
+        then:
+        1 * domainClass.getCompositeIdentity() >> null
+        thrown(MappingException)
+    }
+
+    def "test getHibernateProperties throws exception if a property is 
invalid"() {
+        given:
+        def domainClass = Mock(GrailsHibernatePersistentEntity)
+        def compositeIdentity = new CompositeIdentity(propertyNames: 
['invalid'] as String[])
+
+        when:
+        compositeIdentity.getHibernateProperties(domainClass)
+
+        then:
+        1 * domainClass.getPropertyByName("invalid") >> null
+        thrown(MappingException)
+    }
+}
diff --git 
a/grails-data-hibernate7/core/src/test/groovy/org/grails/orm/hibernate/cfg/domainbinding/CollectionBinderSpec.groovy
 
b/grails-data-hibernate7/core/src/test/groovy/org/grails/orm/hibernate/cfg/domainbinding/CollectionBinderSpec.groovy
index 2726b07ca5..8624f02f5a 100644
--- 
a/grails-data-hibernate7/core/src/test/groovy/org/grails/orm/hibernate/cfg/domainbinding/CollectionBinderSpec.groovy
+++ 
b/grails-data-hibernate7/core/src/test/groovy/org/grails/orm/hibernate/cfg/domainbinding/CollectionBinderSpec.groovy
@@ -107,7 +107,7 @@ class CollectionBinderSpec extends 
HibernateGormDatastoreSpec {
                 manyToOneBinder,
                 propertyFromValueCreator
         )
-        CompositeIdBinder compositeIdBinder = new 
CompositeIdBinder(metadataBuildingContext, componentBinder, componentUpdater)
+        CompositeIdBinder compositeIdBinder = new 
CompositeIdBinder(metadataBuildingContext, componentBinder, componentUpdater, 
propertyBinder)
         PropertyBinder propertyBinderHelper = new PropertyBinder()
         SimpleIdBinder simpleIdBinder = new 
SimpleIdBinder(metadataBuildingContext, namingStrategy, jdbcEnvironment, new 
BasicValueIdCreator(jdbcEnvironment), simpleValueBinder, propertyBinderHelper)
         IdentityBinder identityBinder = new IdentityBinder(simpleIdBinder, 
compositeIdBinder)
diff --git 
a/grails-data-hibernate7/core/src/test/groovy/org/grails/orm/hibernate/cfg/domainbinding/CollectionSecondPassBinderSpec.groovy
 
b/grails-data-hibernate7/core/src/test/groovy/org/grails/orm/hibernate/cfg/domainbinding/CollectionSecondPassBinderSpec.groovy
index 6d4853e5a6..5530b3d9a5 100644
--- 
a/grails-data-hibernate7/core/src/test/groovy/org/grails/orm/hibernate/cfg/domainbinding/CollectionSecondPassBinderSpec.groovy
+++ 
b/grails-data-hibernate7/core/src/test/groovy/org/grails/orm/hibernate/cfg/domainbinding/CollectionSecondPassBinderSpec.groovy
@@ -106,7 +106,7 @@ class CollectionSecondPassBinderSpec extends 
HibernateGormDatastoreSpec {
                 manyToOneBinder,
                 propertyFromValueCreator
         )
-        CompositeIdBinder compositeIdBinder = new 
CompositeIdBinder(metadataBuildingContext, componentBinder, componentUpdater)
+        CompositeIdBinder compositeIdBinder = new 
CompositeIdBinder(metadataBuildingContext, componentBinder, componentUpdater, 
propertyBinder)
         PropertyBinder propertyBinderHelper = new PropertyBinder()
         SimpleIdBinder simpleIdBinder = new 
SimpleIdBinder(metadataBuildingContext, namingStrategy, jdbcEnvironment, new 
BasicValueIdCreator(jdbcEnvironment), simpleValueBinder, propertyBinderHelper)
         IdentityBinder identityBinder = new IdentityBinder(simpleIdBinder, 
compositeIdBinder)
diff --git 
a/grails-data-hibernate7/core/src/test/groovy/org/grails/orm/hibernate/cfg/domainbinding/CompositeIdBinderSpec.groovy
 
b/grails-data-hibernate7/core/src/test/groovy/org/grails/orm/hibernate/cfg/domainbinding/CompositeIdBinderSpec.groovy
index f485126876..a1d27f243a 100644
--- 
a/grails-data-hibernate7/core/src/test/groovy/org/grails/orm/hibernate/cfg/domainbinding/CompositeIdBinderSpec.groovy
+++ 
b/grails-data-hibernate7/core/src/test/groovy/org/grails/orm/hibernate/cfg/domainbinding/CompositeIdBinderSpec.groovy
@@ -32,7 +32,7 @@ class CompositeIdBinderSpec extends 
HibernateGormDatastoreSpec {
 
     def "should bind composite id using property names from 
CompositeIdentity"() {
         given:
-        def domainClass = GroovyMock(GrailsHibernatePersistentEntity)
+        def domainClass = Mock(GrailsHibernatePersistentEntity)
         def metadataBuildingContext = 
getGrailsDomainBinder().getMetadataBuildingContext()
         def root = new RootClass(metadataBuildingContext)
         root.setEntityName("MyEntity")
@@ -40,9 +40,9 @@ class CompositeIdBinderSpec extends 
HibernateGormDatastoreSpec {
         
         def compositeIdentity = new CompositeIdentity(propertyNames: ['prop1', 
'prop2'] as String[])
         
-        def prop1 = GroovyMock(GrailsHibernatePersistentProperty)
-        def prop2 = GroovyMock(GrailsHibernatePersistentProperty)
-        def identifierProp = GroovyMock(GrailsHibernatePersistentProperty)
+        def prop1 = Mock(GrailsHibernatePersistentProperty)
+        def prop2 = Mock(GrailsHibernatePersistentProperty)
+        def identifierProp = Mock(GrailsHibernatePersistentProperty)
         domainClass.getPropertyByName("prop1") >> prop1
         domainClass.getPropertyByName("prop2") >> prop2
         domainClass.getIdentity() >> identifierProp
@@ -64,14 +64,14 @@ class CompositeIdBinderSpec extends 
HibernateGormDatastoreSpec {
 
     def "should fallback to domainClass composite identity when 
CompositeIdentity is null"() {
         given:
-        def domainClass = GroovyMock(GrailsHibernatePersistentEntity)
+        def domainClass = Mock(GrailsHibernatePersistentEntity)
         def metadataBuildingContext = 
getGrailsDomainBinder().getMetadataBuildingContext()
         def root = new RootClass(metadataBuildingContext)
         root.setEntityName("MyEntity")
         def mappings = metadataBuildingContext.getMetadataCollector()
         
-        def prop1 = GroovyMock(GrailsHibernatePersistentProperty)
-        def identifierProp = GroovyMock(GrailsHibernatePersistentProperty)
+        def prop1 = Mock(GrailsHibernatePersistentProperty)
+        def identifierProp = Mock(GrailsHibernatePersistentProperty)
         domainClass.getCompositeIdentity() >> ([prop1] as 
GrailsHibernatePersistentProperty[])
         domainClass.getIdentity() >> identifierProp
         domainClass.getName() >> "MyEntity"
@@ -89,7 +89,7 @@ class CompositeIdBinderSpec extends 
HibernateGormDatastoreSpec {
 
     def "should throw MappingException if no composite properties found"() {
         given:
-        def domainClass = GroovyMock(GrailsHibernatePersistentEntity)
+        def domainClass = Mock(GrailsHibernatePersistentEntity)
         def metadataBuildingContext = 
getGrailsDomainBinder().getMetadataBuildingContext()
         def root = new RootClass(metadataBuildingContext)
         root.setEntityName("MyEntity")
diff --git 
a/grails-data-hibernate7/core/src/test/groovy/org/grails/orm/hibernate/cfg/domainbinding/ListSecondPassBinderSpec.groovy
 
b/grails-data-hibernate7/core/src/test/groovy/org/grails/orm/hibernate/cfg/domainbinding/ListSecondPassBinderSpec.groovy
index 7fcd5ac386..7bbb222ad4 100644
--- 
a/grails-data-hibernate7/core/src/test/groovy/org/grails/orm/hibernate/cfg/domainbinding/ListSecondPassBinderSpec.groovy
+++ 
b/grails-data-hibernate7/core/src/test/groovy/org/grails/orm/hibernate/cfg/domainbinding/ListSecondPassBinderSpec.groovy
@@ -106,7 +106,7 @@ class ListSecondPassBinderSpec extends 
HibernateGormDatastoreSpec {
                 manyToOneBinder,
                 propertyFromValueCreator
         )
-        CompositeIdBinder compositeIdBinder = new 
CompositeIdBinder(metadataBuildingContext, componentBinder, componentUpdater)
+        CompositeIdBinder compositeIdBinder = new 
CompositeIdBinder(metadataBuildingContext, componentBinder, componentUpdater, 
propertyBinder)
         PropertyBinder propertyBinderHelper = new PropertyBinder()
         SimpleIdBinder simpleIdBinder = new 
SimpleIdBinder(metadataBuildingContext, namingStrategy, jdbcEnvironment, new 
BasicValueIdCreator(jdbcEnvironment), simpleValueBinder, propertyBinderHelper)
         IdentityBinder identityBinder = new IdentityBinder(simpleIdBinder, 
compositeIdBinder)
diff --git 
a/grails-data-hibernate7/core/src/test/groovy/org/grails/orm/hibernate/cfg/domainbinding/MapSecondPassBinderSpec.groovy
 
b/grails-data-hibernate7/core/src/test/groovy/org/grails/orm/hibernate/cfg/domainbinding/MapSecondPassBinderSpec.groovy
index 2b18aac309..fb869edfe0 100644
--- 
a/grails-data-hibernate7/core/src/test/groovy/org/grails/orm/hibernate/cfg/domainbinding/MapSecondPassBinderSpec.groovy
+++ 
b/grails-data-hibernate7/core/src/test/groovy/org/grails/orm/hibernate/cfg/domainbinding/MapSecondPassBinderSpec.groovy
@@ -106,7 +106,7 @@ class MapSecondPassBinderSpec extends 
HibernateGormDatastoreSpec {
                 manyToOneBinder,
                 propertyFromValueCreator
         )
-        CompositeIdBinder compositeIdBinder = new 
CompositeIdBinder(metadataBuildingContext, componentBinder, componentUpdater)
+        CompositeIdBinder compositeIdBinder = new 
CompositeIdBinder(metadataBuildingContext, componentBinder, componentUpdater, 
propertyBinder)
         PropertyBinder propertyBinderHelper = new PropertyBinder()
         SimpleIdBinder simpleIdBinder = new 
SimpleIdBinder(metadataBuildingContext, namingStrategy, jdbcEnvironment, new 
BasicValueIdCreator(jdbcEnvironment), simpleValueBinder, propertyBinderHelper)
         IdentityBinder identityBinder = new IdentityBinder(simpleIdBinder, 
compositeIdBinder)

Reply via email to