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 cbbc30c78c9d774f7dae6ab3631bec5eafc0b769
Author: Walter Duque de Estrada <[email protected]>
AuthorDate: Sun Feb 15 18:13:51 2026 -0600

    Refactor class properties binding logic from GrailsDomainBinder to 
ClassPropertiesBinder and clean up binder signatures.
---
 .../orm/hibernate/cfg/GrailsDomainBinder.java      | 50 ++++++-------------
 .../binder/ClassPropertiesBinder.java              | 56 +++++++++++++++++++++
 .../binder/ClassPropertiesBinderSpec.groovy        | 57 ++++++++++++++++++++++
 3 files changed, 127 insertions(+), 36 deletions(-)

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 11358ac2fc..d64e6b569a 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
@@ -18,6 +18,7 @@ import groovy.lang.Closure;
 
 import org.grails.datastore.mapping.model.config.GormProperties;
 import org.grails.datastore.mapping.model.types.TenantId;
+import org.grails.orm.hibernate.cfg.domainbinding.binder.ClassPropertiesBinder;
 import org.grails.orm.hibernate.cfg.domainbinding.binder.ClassBinder;
 import 
org.grails.orm.hibernate.cfg.domainbinding.binder.ColumnConfigToColumnBinder;
 import 
org.grails.orm.hibernate.cfg.domainbinding.binder.ComponentPropertyBinder;
@@ -230,6 +231,8 @@ public class GrailsDomainBinder
         SimpleIdBinder simpleIdBinder = new 
SimpleIdBinder(metadataBuildingContext, namingStrategy, jdbcEnvironment, new 
BasicValueIdCreator(jdbcEnvironment), simpleValueBinder, propertyBinder);
         IdentityBinder identityBinder = new IdentityBinder(simpleIdBinder, 
compositeIdBinder);
         VersionBinder versionBinder = new 
VersionBinder(metadataBuildingContext, simpleValueBinder, propertyBinder, 
BasicValue::new);
+        NaturalIdentifierBinder naturalIdentifierBinder = new 
NaturalIdentifierBinder();
+        ClassPropertiesBinder classPropertiesBinder = new 
ClassPropertiesBinder(grailsPropertyBinder, propertyFromValueCreator, 
naturalIdentifierBinder);
         MultiTenantFilterBinder multiTenantFilterBinder = new 
MultiTenantFilterBinder();
         JoinedSubClassBinder joinedSubClassBinder = new 
JoinedSubClassBinder(metadataBuildingContext, namingStrategy, new 
SimpleValueColumnBinder(), columnNameForPropertyAndPathFetcher, classBinder);
         UnionSubclassBinder unionSubclassBinder = new 
UnionSubclassBinder(metadataBuildingContext, namingStrategy, classBinder);
@@ -239,7 +242,7 @@ public class GrailsDomainBinder
                 .getHibernatePersistentEntities(dataSourceName)
                 .stream()
                 .filter(persistentEntity -> 
persistentEntity.forGrailsDomainMapping(dataSourceName))
-                .forEach(hibernatePersistentEntity -> 
bindRoot(hibernatePersistentEntity, metadataCollector, sessionFactoryName, 
defaultColumnNameFetcher, columnNameForPropertyAndPathFetcher, identityBinder, 
versionBinder, grailsPropertyBinder, classBinder, propertyFromValueCreator, 
multiTenantFilterBinder, joinedSubClassBinder, unionSubclassBinder, 
singleTableSubclassBinder));
+                .forEach(hibernatePersistentEntity -> 
bindRoot(hibernatePersistentEntity, metadataCollector, sessionFactoryName, 
defaultColumnNameFetcher, identityBinder, versionBinder, classBinder, 
classPropertiesBinder, multiTenantFilterBinder, joinedSubClassBinder, 
unionSubclassBinder, singleTableSubclassBinder));
     }
 
 
@@ -270,20 +273,20 @@ public class GrailsDomainBinder
      * @param mappings    The Hibernate Mappings object
      * @param sessionFactoryBeanName  the session factory bean name
      */
-    protected void bindRoot(@Nonnull GrailsHibernatePersistentEntity 
entity,@Nonnull InFlightMetadataCollector mappings, String 
sessionFactoryBeanName, DefaultColumnNameFetcher defaultColumnNameFetcher, 
ColumnNameForPropertyAndPathFetcher columnNameForPropertyAndPathFetcher, 
IdentityBinder identityBinder, VersionBinder versionBinder, 
GrailsPropertyBinder grailsPropertyBinder, ClassBinder classBinder, 
PropertyFromValueCreator propertyFromValueCreator, MultiTenantFilterBinder 
multiTenantFi [...]
+    protected void bindRoot(@Nonnull GrailsHibernatePersistentEntity 
entity,@Nonnull InFlightMetadataCollector mappings, String 
sessionFactoryBeanName, DefaultColumnNameFetcher defaultColumnNameFetcher, 
IdentityBinder identityBinder, VersionBinder versionBinder, ClassBinder 
classBinder, ClassPropertiesBinder classPropertiesBinder, 
MultiTenantFilterBinder multiTenantFilterBinder, JoinedSubClassBinder 
joinedSubClassBinder, UnionSubclassBinder unionSubclassBinder, 
SingleTableSubclassBinder  [...]
         if (mappings.getEntityBinding(entity.getName()) != null) {
             LOG.info("[GrailsDomainBinder] Class [" + entity.getName() + "] is 
already mapped, skipping.. ");
             return;
         }
         var children = entity.getChildEntities(dataSourceName);
-        RootClass root = bindRootPersistentClassCommonValues(entity, children, 
mappings, sessionFactoryBeanName, identityBinder, versionBinder, 
grailsPropertyBinder, classBinder, propertyFromValueCreator);
+        RootClass root = bindRootPersistentClassCommonValues(entity, children, 
mappings, sessionFactoryBeanName, identityBinder, versionBinder, classBinder, 
classPropertiesBinder);
         Mapping m = entity.getMappedForm();
         final Mapping finalMapping = m;
         if (!children.isEmpty() && entity.isTablePerHierarchy()) {
             bindDiscriminatorProperty(root, m);
         }
         // bind the sub classes
-        children.forEach(sub -> bindSubClass(sub, root, mappings, 
sessionFactoryBeanName, finalMapping,mappingCacheHolder, 
defaultColumnNameFetcher, columnNameForPropertyAndPathFetcher, 
grailsPropertyBinder, classBinder, propertyFromValueCreator, 
multiTenantFilterBinder, joinedSubClassBinder, unionSubclassBinder, 
singleTableSubclassBinder));
+        children.forEach(sub -> bindSubClass(sub, root, mappings, 
sessionFactoryBeanName, finalMapping,mappingCacheHolder, 
defaultColumnNameFetcher, classBinder, classPropertiesBinder, 
multiTenantFilterBinder, joinedSubClassBinder, unionSubclassBinder, 
singleTableSubclassBinder));
 
         multiTenantFilterBinder.addMultiTenantFilterIfNecessary(entity, root, 
mappings, defaultColumnNameFetcher);
 
@@ -312,9 +315,9 @@ public class GrailsDomainBinder
                               PersistentClass parent,
                               @Nonnull InFlightMetadataCollector mappings,
                               String sessionFactoryBeanName
-                            , Mapping m, MappingCacheHolder 
mappingCacheHolder, DefaultColumnNameFetcher defaultColumnNameFetcher, 
ColumnNameForPropertyAndPathFetcher columnNameForPropertyAndPathFetcher, 
GrailsPropertyBinder grailsPropertyBinder, ClassBinder classBinder, 
PropertyFromValueCreator propertyFromValueCreator, MultiTenantFilterBinder 
multiTenantFilterBinder, JoinedSubClassBinder joinedSubClassBinder, 
UnionSubclassBinder unionSubclassBinder, SingleTableSubclassBinder singleTabl 
[...]
+                            , Mapping m, MappingCacheHolder 
mappingCacheHolder, DefaultColumnNameFetcher defaultColumnNameFetcher, 
ClassBinder classBinder, ClassPropertiesBinder classPropertiesBinder, 
MultiTenantFilterBinder multiTenantFilterBinder, JoinedSubClassBinder 
joinedSubClassBinder, UnionSubclassBinder unionSubclassBinder, 
SingleTableSubclassBinder singleTableSubclassBinder) {
         mappingCacheHolder.cacheMapping(sub);
-        Subclass subClass = createSubclassMapping(sub, parent, mappings, 
sessionFactoryBeanName, m, defaultColumnNameFetcher, 
columnNameForPropertyAndPathFetcher, grailsPropertyBinder, classBinder, 
propertyFromValueCreator, multiTenantFilterBinder, joinedSubClassBinder, 
unionSubclassBinder, singleTableSubclassBinder);
+        Subclass subClass = createSubclassMapping(sub, parent, mappings, 
sessionFactoryBeanName, m, defaultColumnNameFetcher, classBinder, 
classPropertiesBinder, multiTenantFilterBinder, joinedSubClassBinder, 
unionSubclassBinder, singleTableSubclassBinder);
 
 
         parent.addSubclass(subClass);
@@ -325,11 +328,11 @@ public class GrailsDomainBinder
         var children = sub.getChildEntities(dataSourceName);
         if (!children.isEmpty()) {
             // bind the sub classes
-            children.forEach(sub1 -> bindSubClass(sub1, subClass, mappings, 
sessionFactoryBeanName, m,mappingCacheHolder, defaultColumnNameFetcher, 
columnNameForPropertyAndPathFetcher, grailsPropertyBinder, classBinder, 
propertyFromValueCreator, multiTenantFilterBinder, joinedSubClassBinder, 
unionSubclassBinder, singleTableSubclassBinder ));
+            children.forEach(sub1 -> bindSubClass(sub1, subClass, mappings, 
sessionFactoryBeanName, m,mappingCacheHolder, defaultColumnNameFetcher, 
classBinder, classPropertiesBinder, multiTenantFilterBinder, 
joinedSubClassBinder, unionSubclassBinder, singleTableSubclassBinder ));
         }
     }
 
-    private @NonNull Subclass createSubclassMapping(@NonNull 
GrailsHibernatePersistentEntity subEntity, PersistentClass parent, @NonNull 
InFlightMetadataCollector mappings, String sessionFactoryBeanName, Mapping m, 
DefaultColumnNameFetcher defaultColumnNameFetcher, 
ColumnNameForPropertyAndPathFetcher columnNameForPropertyAndPathFetcher, 
GrailsPropertyBinder grailsPropertyBinder, ClassBinder classBinder, 
PropertyFromValueCreator propertyFromValueCreator, MultiTenantFilterBinder 
multiTenan [...]
+    private @NonNull Subclass createSubclassMapping(@NonNull 
GrailsHibernatePersistentEntity subEntity, PersistentClass parent, @NonNull 
InFlightMetadataCollector mappings, String sessionFactoryBeanName, Mapping m, 
DefaultColumnNameFetcher defaultColumnNameFetcher, ClassBinder classBinder, 
ClassPropertiesBinder classPropertiesBinder, MultiTenantFilterBinder 
multiTenantFilterBinder, JoinedSubClassBinder joinedSubClassBinder, 
UnionSubclassBinder unionSubclassBinder, SingleTableSubclassBind [...]
         Subclass subClass;
         subEntity.configureDerivedProperties();
         if (!m.getTablePerHierarchy() && !m.isTablePerConcreteClass()) {
@@ -355,7 +358,7 @@ public class GrailsDomainBinder
         subClass.setAbstract(subEntity.isAbstract());
         subClass.setEntityName(subEntity.getName());
         
subClass.setJpaEntityName(GrailsHibernateUtil.unqualify(subEntity.getName()));
-        createClassProperties(subEntity, subClass, mappings, 
sessionFactoryBeanName, grailsPropertyBinder, propertyFromValueCreator);
+        classPropertiesBinder.bindClassProperties(subEntity, subClass, 
mappings, sessionFactoryBeanName);
         return subClass;
     }
 
@@ -427,9 +430,8 @@ public class GrailsDomainBinder
                                                        String 
sessionFactoryBeanName,
                                                        IdentityBinder 
identityBinder,
                                                        VersionBinder 
versionBinder,
-                                                       GrailsPropertyBinder 
grailsPropertyBinder,
                                                        ClassBinder classBinder,
-                                                       
PropertyFromValueCreator propertyFromValueCreator
+                                                       ClassPropertiesBinder 
classPropertiesBinder
     ) {
 
         RootClass root = new RootClass(this.metadataBuildingContext);
@@ -475,36 +477,12 @@ public class GrailsDomainBinder
         identityBinder.bindIdentity(domainClass, root, mappings, gormMapping, 
sessionFactoryBeanName);
         versionBinder.bindVersion(domainClass.getVersion(), root);
         root.createPrimaryKey();
-        createClassProperties(domainClass, root, mappings, 
sessionFactoryBeanName, grailsPropertyBinder, propertyFromValueCreator);
+        classPropertiesBinder.bindClassProperties(domainClass, root, mappings, 
sessionFactoryBeanName);
 
         return root;
     }
 
 
-    /**
-     * Creates and binds the properties for the specified Grails domain class 
and PersistentClass
-     * and binds them to the Hibernate runtime meta model
-     *
-     * @param domainClass     The Grails domain class
-     * @param persistentClass The Hibernate PersistentClass instance
-     * @param mappings        The Hibernate Mappings instance
-     * @param sessionFactoryBeanName  the session factory bean name
-     */
-    private void createClassProperties(@Nonnull 
GrailsHibernatePersistentEntity domainClass, PersistentClass persistentClass,
-                                         @Nonnull InFlightMetadataCollector 
mappings, String sessionFactoryBeanName, GrailsPropertyBinder 
grailsPropertyBinder, PropertyFromValueCreator propertyFromValueCreator) {
-
-
-
-        for (GrailsHibernatePersistentProperty currentGrailsProp : 
domainClass.getPersistentPropertiesToBind()) {
-           var value = grailsPropertyBinder.bindProperty(persistentClass, 
currentGrailsProp, mappings, sessionFactoryBeanName);
-           
persistentClass.addProperty(propertyFromValueCreator.createProperty(value, 
currentGrailsProp));
-        }
-
-        new 
NaturalIdentifierBinder().bindNaturalIdentifier(domainClass.getMappedForm(), 
persistentClass);
-    }
-
-
-
     public MetadataBuildingContext getMetadataBuildingContext() {
         return metadataBuildingContext;
     }
diff --git 
a/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/cfg/domainbinding/binder/ClassPropertiesBinder.java
 
b/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/cfg/domainbinding/binder/ClassPropertiesBinder.java
new file mode 100644
index 0000000000..f8f32804c4
--- /dev/null
+++ 
b/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/cfg/domainbinding/binder/ClassPropertiesBinder.java
@@ -0,0 +1,56 @@
+package org.grails.orm.hibernate.cfg.domainbinding.binder;
+
+import jakarta.annotation.Nonnull;
+import org.grails.orm.hibernate.cfg.GrailsHibernatePersistentEntity;
+import org.grails.orm.hibernate.cfg.GrailsHibernatePersistentProperty;
+import 
org.grails.orm.hibernate.cfg.domainbinding.util.PropertyFromValueCreator;
+import org.hibernate.boot.spi.InFlightMetadataCollector;
+import org.hibernate.mapping.PersistentClass;
+import org.hibernate.mapping.Value;
+
+/**
+ * Binds the properties of a Grails domain class to the Hibernate meta-model.
+ *
+ * @author Graeme Rocher
+ * @since 7.0
+ */
+public class ClassPropertiesBinder {
+
+    private final GrailsPropertyBinder grailsPropertyBinder;
+    private final PropertyFromValueCreator propertyFromValueCreator;
+    private final NaturalIdentifierBinder naturalIdentifierBinder;
+
+    public ClassPropertiesBinder(GrailsPropertyBinder grailsPropertyBinder,
+                                 PropertyFromValueCreator 
propertyFromValueCreator,
+                                 NaturalIdentifierBinder 
naturalIdentifierBinder) {
+        this.grailsPropertyBinder = grailsPropertyBinder;
+        this.propertyFromValueCreator = propertyFromValueCreator;
+        this.naturalIdentifierBinder = naturalIdentifierBinder;
+    }
+
+    public ClassPropertiesBinder(GrailsPropertyBinder grailsPropertyBinder,
+                                 PropertyFromValueCreator 
propertyFromValueCreator) {
+        this(grailsPropertyBinder, propertyFromValueCreator, new 
NaturalIdentifierBinder());
+    }
+
+    /**
+     * Binds the properties of the specified Grails domain class to the 
Hibernate meta-model.
+     *
+     * @param domainClass The Grails domain class
+     * @param persistentClass The Hibernate PersistentClass instance
+     * @param mappings The Hibernate InFlightMetadataCollector instance
+     * @param sessionFactoryBeanName The session factory bean name
+     */
+    public void bindClassProperties(@Nonnull GrailsHibernatePersistentEntity 
domainClass,
+                                    PersistentClass persistentClass,
+                                    @Nonnull InFlightMetadataCollector 
mappings,
+                                    String sessionFactoryBeanName) {
+
+        for (GrailsHibernatePersistentProperty currentGrailsProp : 
domainClass.getPersistentPropertiesToBind()) {
+            Value value = grailsPropertyBinder.bindProperty(persistentClass, 
currentGrailsProp, mappings, sessionFactoryBeanName);
+            
persistentClass.addProperty(propertyFromValueCreator.createProperty(value, 
currentGrailsProp));
+        }
+
+        
naturalIdentifierBinder.bindNaturalIdentifier(domainClass.getMappedForm(), 
persistentClass);
+    }
+}
diff --git 
a/grails-data-hibernate7/core/src/test/groovy/org/grails/orm/hibernate/cfg/domainbinding/binder/ClassPropertiesBinderSpec.groovy
 
b/grails-data-hibernate7/core/src/test/groovy/org/grails/orm/hibernate/cfg/domainbinding/binder/ClassPropertiesBinderSpec.groovy
new file mode 100644
index 0000000000..c096318426
--- /dev/null
+++ 
b/grails-data-hibernate7/core/src/test/groovy/org/grails/orm/hibernate/cfg/domainbinding/binder/ClassPropertiesBinderSpec.groovy
@@ -0,0 +1,57 @@
+package org.grails.orm.hibernate.cfg.domainbinding.binder
+
+import grails.gorm.specs.HibernateGormDatastoreSpec
+import org.grails.orm.hibernate.cfg.GrailsHibernatePersistentEntity
+import org.grails.orm.hibernate.cfg.GrailsHibernatePersistentProperty
+import org.grails.orm.hibernate.cfg.Mapping
+import org.grails.orm.hibernate.cfg.domainbinding.util.PropertyFromValueCreator
+import org.hibernate.boot.spi.InFlightMetadataCollector
+import org.hibernate.mapping.Property
+import org.hibernate.mapping.RootClass
+import org.hibernate.mapping.Value
+
+class ClassPropertiesBinderSpec extends HibernateGormDatastoreSpec {
+
+    void "test bindClassProperties"() {
+        given:
+        def grailsPropertyBinder = Mock(GrailsPropertyBinder)
+        def propertyFromValueCreator = Mock(PropertyFromValueCreator)
+        def naturalIdentifierBinder = Mock(NaturalIdentifierBinder)
+        def binder = new ClassPropertiesBinder(grailsPropertyBinder, 
propertyFromValueCreator, naturalIdentifierBinder)
+
+        def domainClass = Mock(GrailsHibernatePersistentEntity)
+        def persistentClass = new 
RootClass(getGrailsDomainBinder().getMetadataBuildingContext())
+        def mappings = Mock(InFlightMetadataCollector)
+        def sessionFactoryBeanName = "sessionFactory"
+
+        def prop1 = Mock(GrailsHibernatePersistentProperty)
+        def prop2 = Mock(GrailsHibernatePersistentProperty)
+        domainClass.getPersistentPropertiesToBind() >> [prop1, prop2]
+        
+        def value1 = Mock(Value)
+        def value2 = Mock(Value)
+        
+        def hibernateProp1 = new Property()
+        hibernateProp1.setName("hibernateProp1")
+        def hibernateProp2 = new Property()
+        hibernateProp2.setName("hibernateProp2")
+        
+        def mapping = Mock(Mapping)
+        domainClass.getMappedForm() >> mapping
+
+        when:
+        binder.bindClassProperties(domainClass, persistentClass, mappings, 
sessionFactoryBeanName)
+
+        then:
+        1 * grailsPropertyBinder.bindProperty(persistentClass, prop1, 
mappings, sessionFactoryBeanName) >> value1
+        1 * propertyFromValueCreator.createProperty(value1, prop1) >> 
hibernateProp1
+
+        1 * grailsPropertyBinder.bindProperty(persistentClass, prop2, 
mappings, sessionFactoryBeanName) >> value2
+        1 * propertyFromValueCreator.createProperty(value2, prop2) >> 
hibernateProp2
+
+        persistentClass.getProperty("hibernateProp1") == hibernateProp1
+        persistentClass.getProperty("hibernateProp2") == hibernateProp2
+
+        1 * naturalIdentifierBinder.bindNaturalIdentifier(mapping, 
persistentClass)
+    }
+}

Reply via email to