You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@grails.apache.org by bo...@apache.org on 2026/02/16 00:14:23 UTC
(grails-core) 16/16: Refactor class properties binding logic from GrailsDomainBinder to ClassPropertiesBinder and clean up binder signatures.
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 <wb...@mac.com>
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)
+ }
+}