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) + } +}
