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)
