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 869d405d6d249524e202410a33825b6397edd42e Author: Walter Duque de Estrada <[email protected]> AuthorDate: Fri Feb 6 17:28:08 2026 -0600 GrailsDomainBinder --- .../orm/hibernate/cfg/GrailsDomainBinder.java | 3 +- .../cfg/domainbinding/GrailsPropertyBinder.java | 13 +-- .../domainbinding/GrailsPropertyBinderSpec.groovy | 96 +++++++++++++++------- 3 files changed, 73 insertions(+), 39 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 83a848bb36..031465217d 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 @@ -694,7 +694,8 @@ public class GrailsDomainBinder for (GrailsHibernatePersistentProperty currentGrailsProp : domainClass.getPersistentPropertiesToBind()) { - grailsPropertyBinder.bindProperty(persistentClass, mappings, sessionFactoryBeanName, currentGrailsProp); + var value = grailsPropertyBinder.bindProperty(persistentClass, mappings, sessionFactoryBeanName, currentGrailsProp); + persistentClass.addProperty(propertyFromValueCreator.createProperty(value, currentGrailsProp)); } new NaturalIdentifierBinder().bindNaturalIdentifier(domainClass.getMappedForm(), persistentClass); diff --git a/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/cfg/domainbinding/GrailsPropertyBinder.java b/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/cfg/domainbinding/GrailsPropertyBinder.java index 12bcf99a15..604b123e91 100644 --- a/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/cfg/domainbinding/GrailsPropertyBinder.java +++ b/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/cfg/domainbinding/GrailsPropertyBinder.java @@ -17,7 +17,6 @@ import org.hibernate.mapping.Component; import org.hibernate.mapping.ManyToOne; import org.hibernate.mapping.OneToOne; import org.hibernate.mapping.PersistentClass; -import org.hibernate.mapping.Property; import org.hibernate.mapping.SimpleValue; import org.hibernate.mapping.Table; import org.hibernate.mapping.Value; @@ -31,12 +30,10 @@ public class GrailsPropertyBinder { private static final Logger LOG = LoggerFactory.getLogger(GrailsPropertyBinder.class); private final MetadataBuildingContext metadataBuildingContext; - private final PersistentEntityNamingStrategy namingStrategy; private final CollectionHolder collectionHolder; private final EnumTypeBinder enumTypeBinder; private final ComponentPropertyBinder componentPropertyBinder; private final CollectionBinder collectionBinder; - private final PropertyFromValueCreator propertyFromValueCreator; private final SimpleValueBinder simpleValueBinder; private final ColumnNameForPropertyAndPathFetcher columnNameForPropertyAndPathFetcher; private final OneToOneBinder oneToOneBinder; @@ -56,7 +53,6 @@ public class GrailsPropertyBinder { enumTypeBinder, componentPropertyBinder, collectionBinder, - propertyFromValueCreator, new SimpleValueBinder(namingStrategy), new ColumnNameForPropertyAndPathFetcher(namingStrategy), new OneToOneBinder(namingStrategy), @@ -70,25 +66,22 @@ public class GrailsPropertyBinder { EnumTypeBinder enumTypeBinder, ComponentPropertyBinder componentPropertyBinder, CollectionBinder collectionBinder, - PropertyFromValueCreator propertyFromValueCreator, SimpleValueBinder simpleValueBinder, ColumnNameForPropertyAndPathFetcher columnNameForPropertyAndPathFetcher, OneToOneBinder oneToOneBinder, ManyToOneBinder manyToOneBinder) { this.metadataBuildingContext = metadataBuildingContext; - this.namingStrategy = namingStrategy; this.collectionHolder = collectionHolder; this.enumTypeBinder = enumTypeBinder; this.componentPropertyBinder = componentPropertyBinder; this.collectionBinder = collectionBinder; - this.propertyFromValueCreator = propertyFromValueCreator; this.simpleValueBinder = simpleValueBinder; this.columnNameForPropertyAndPathFetcher = columnNameForPropertyAndPathFetcher; this.oneToOneBinder = oneToOneBinder; this.manyToOneBinder = manyToOneBinder; } - public void bindProperty(PersistentClass persistentClass + public Value bindProperty(PersistentClass persistentClass , @Nonnull InFlightMetadataCollector mappings , String sessionFactoryBeanName , @Nonnull GrailsHibernatePersistentProperty currentGrailsProp) { @@ -154,7 +147,7 @@ public class GrailsPropertyBinder { // After creating the value and applying binders (where applicable), create and add the property. // This is now done once at the end of the consolidated block. - Property property = propertyFromValueCreator.createProperty(value, currentGrailsProp); - persistentClass.addProperty(property); + + return value; } } \ No newline at end of file diff --git a/grails-data-hibernate7/core/src/test/groovy/org/grails/orm/hibernate/cfg/domainbinding/GrailsPropertyBinderSpec.groovy b/grails-data-hibernate7/core/src/test/groovy/org/grails/orm/hibernate/cfg/domainbinding/GrailsPropertyBinderSpec.groovy index ab4324a6a4..4552bc65f9 100644 --- a/grails-data-hibernate7/core/src/test/groovy/org/grails/orm/hibernate/cfg/domainbinding/GrailsPropertyBinderSpec.groovy +++ b/grails-data-hibernate7/core/src/test/groovy/org/grails/orm/hibernate/cfg/domainbinding/GrailsPropertyBinderSpec.groovy @@ -6,10 +6,31 @@ import org.grails.orm.hibernate.cfg.GrailsHibernatePersistentEntity import org.grails.orm.hibernate.cfg.GrailsHibernatePersistentProperty import org.grails.orm.hibernate.cfg.GrailsDomainBinder import org.hibernate.mapping.ManyToOne -import org.hibernate.mapping.OneToOne // Import OneToOne import org.hibernate.mapping.Property import org.hibernate.mapping.RootClass import org.hibernate.mapping.SimpleValue +import org.grails.orm.hibernate.cfg.PropertyConfig +import org.grails.orm.hibernate.cfg.ColumnConfig +import org.grails.orm.hibernate.cfg.domainbinding.collectionType.CollectionHolder +import org.grails.orm.hibernate.cfg.domainbinding.collectionType.CollectionType +import org.hibernate.boot.spi.InFlightMetadataCollector +import org.hibernate.boot.spi.MetadataBuildingContext +import org.hibernate.mapping.BasicValue +import org.hibernate.mapping.Collection +import org.hibernate.mapping.Component +import org.hibernate.mapping.OneToOne +import org.hibernate.mapping.PersistentClass +import org.hibernate.mapping.Table +import org.hibernate.mapping.Value +import org.slf4j.Logger +import org.slf4j.LoggerFactory + +import java.util.Arrays +import java.util.HashMap +import java.util.Properties +import java.util.Optional + +import static org.grails.orm.hibernate.cfg.GrailsDomainBinder.EMPTY_PATH class GrailsPropertyBinderSpec extends HibernateGormDatastoreSpec { @@ -35,7 +56,8 @@ class GrailsPropertyBinderSpec extends HibernateGormDatastoreSpec { when: def titleProp = persistentEntity.getPropertyByName("title") as GrailsHibernatePersistentProperty - propertyBinder.bindProperty(rootClass, collector, "sessionFactory", titleProp) + Value value = propertyBinder.bindProperty(rootClass, collector, "sessionFactory", titleProp) + rootClass.addProperty(binder.getPropertyFromValueCreator().createProperty(value, titleProp)) then: Property prop = rootClass.getProperty("title") @@ -56,7 +78,8 @@ class GrailsPropertyBinderSpec extends HibernateGormDatastoreSpec { when: def statusProp = persistentEntity.getPropertyByName("status") as GrailsHibernatePersistentProperty - propertyBinder.bindProperty(rootClass, collector, "sessionFactory", statusProp) + Value value = propertyBinder.bindProperty(rootClass, collector, "sessionFactory", statusProp) + rootClass.addProperty(binder.getPropertyFromValueCreator().createProperty(value, statusProp)) then: Property prop = rootClass.getProperty("status") @@ -81,7 +104,8 @@ class GrailsPropertyBinderSpec extends HibernateGormDatastoreSpec { when: def ownerProp = petEntity.getPropertyByName("owner") as GrailsHibernatePersistentProperty - propertyBinder.bindProperty(rootClass, collector, "sessionFactory", ownerProp) + Value value = propertyBinder.bindProperty(rootClass, collector, "sessionFactory", ownerProp) + rootClass.addProperty(binder.getPropertyFromValueCreator().createProperty(value, ownerProp)) then: Property prop = rootClass.getProperty("owner") @@ -103,7 +127,8 @@ class GrailsPropertyBinderSpec extends HibernateGormDatastoreSpec { when: def addressProp = persistentEntity.getPropertyByName("homeAddress") as GrailsHibernatePersistentProperty - propertyBinder.bindProperty(rootClass, collector, "sessionFactory", addressProp) + Value value = propertyBinder.bindProperty(rootClass, collector, "sessionFactory", addressProp) + rootClass.addProperty(binder.getPropertyFromValueCreator().createProperty(value, addressProp)) then: Property prop = rootClass.getProperty("homeAddress") @@ -130,7 +155,8 @@ class GrailsPropertyBinderSpec extends HibernateGormDatastoreSpec { when: def petsProp = personEntity.getPropertyByName("pets") as GrailsHibernatePersistentProperty - propertyBinder.bindProperty(rootClass, collector, "sessionFactory", petsProp) + Value value = propertyBinder.bindProperty(rootClass, collector, "sessionFactory", petsProp) + rootClass.addProperty(binder.getPropertyFromValueCreator().createProperty(value, petsProp)) then: Property prop = rootClass.getProperty("pets") @@ -168,7 +194,8 @@ class GrailsPropertyBinderSpec extends HibernateGormDatastoreSpec { when: def booksProp = authorEntity.getPropertyByName("books") as GrailsHibernatePersistentProperty - propertyBinder.bindProperty(rootClass, collector, "sessionFactory", booksProp) + Value value = propertyBinder.bindProperty(rootClass, collector, "sessionFactory", booksProp) + rootClass.addProperty(binder.getPropertyFromValueCreator().createProperty(value, booksProp)) collector.processSecondPasses(binder.getMetadataBuildingContext()) then: @@ -206,7 +233,8 @@ class GrailsPropertyBinderSpec extends HibernateGormDatastoreSpec { when: def booksProp = authorEntity.getPropertyByName("books") as GrailsHibernatePersistentProperty - propertyBinder.bindProperty(rootClass, collector, "sessionFactory", booksProp) + Value value = propertyBinder.bindProperty(rootClass, collector, "sessionFactory", booksProp) + rootClass.addProperty(binder.getPropertyFromValueCreator().createProperty(value, booksProp)) collector.processSecondPasses(binder.getMetadataBuildingContext()) then: @@ -266,7 +294,8 @@ class GrailsPropertyBinderSpec extends HibernateGormDatastoreSpec { when: def childBookProp = authorEntity.getPropertyByName("childBook") as GrailsHibernatePersistentProperty - propertyBinder.bindProperty(rootClass, collector, "sessionFactory", childBookProp) + Value value = propertyBinder.bindProperty(rootClass, collector, "sessionFactory", childBookProp) + rootClass.addProperty(binder.getPropertyFromValueCreator().createProperty(value, childBookProp)) // Process second passes to ensure Hibernate's internal mappings are finalized collector.processSecondPasses(binder.getMetadataBuildingContext()) @@ -287,12 +316,9 @@ class GrailsPropertyBinderSpec extends HibernateGormDatastoreSpec { def enumTypeBinder = Mock(EnumTypeBinder) def componentPropertyBinder = Mock(ComponentPropertyBinder) def collectionBinder = Mock(CollectionBinder) - def propertyFromValueCreator = Mock(PropertyFromValueCreator) - def simpleValueBinder = Mock(SimpleValueBinder) - def columnNameForPropertyAndPathFetcher = Mock(ColumnNameForPropertyAndPathFetcher) - def oneToOneBinder = Mock(OneToOneBinder) - def manyToOneBinder = Mock(ManyToOneBinder) + def propertyFromValueCreator = Mock(PropertyFromValueCreator) // Mock propertyFromValueCreator as it is a constructor parameter + // Instantiate GrailsPropertyBinder using the protected constructor with necessary mocks def propertyBinder = new GrailsPropertyBinder( metadataBuildingContext, namingStrategy, @@ -300,11 +326,7 @@ class GrailsPropertyBinderSpec extends HibernateGormDatastoreSpec { enumTypeBinder, componentPropertyBinder, collectionBinder, - propertyFromValueCreator, - simpleValueBinder, - columnNameForPropertyAndPathFetcher, - oneToOneBinder, - manyToOneBinder + propertyFromValueCreator ) def mappings = Mock(org.hibernate.boot.spi.InFlightMetadataCollector) @@ -314,23 +336,41 @@ class GrailsPropertyBinderSpec extends HibernateGormDatastoreSpec { def currentGrailsProp = Mock(GrailsHibernatePersistentProperty) def table = new org.hibernate.mapping.Table("TEST_TABLE") rootClass.setTable(table) - def owner = Mock(org.grails.orm.hibernate.cfg.GrailsHibernatePersistentEntity) - currentGrailsProp.getHibernateOwner() >> owner - owner.getMappedForm() >> new org.grails.orm.hibernate.cfg.Mapping() + // Mocking currentGrailsProp and its dependencies to prevent NPEs + def mockOwner = Mock(org.grails.orm.hibernate.cfg.GrailsHibernatePersistentEntity) + def mockMapping = new org.grails.orm.hibernate.cfg.Mapping() + mockMapping.setComment("test comment") // Provide a comment + currentGrailsProp.getHibernateOwner() >> mockOwner + mockOwner.getMappedForm() >> mockMapping // Return the Mapping object + + // Stubbing getOwner() to return mockOwner + currentGrailsProp.getOwner() >> mockOwner + mockOwner.isRoot() >> true // Stub isRoot() to prevent NPE in ColumnBinder + + // Mock PropertyConfig and stub its methods for SimpleValueBinder + def propertyConfigMock = Mock(PropertyConfig) + currentGrailsProp.getMappedForm() >> propertyConfigMock // For SimpleValueBinder logic, need PropertyConfig + + propertyConfigMock.getGenerator() >> null + propertyConfigMock.getTypeParams() >> new Properties() + propertyConfigMock.isDerived() >> false + def columnConfigMock = Mock(ColumnConfig) // Mock ColumnConfig for getColumns() + columnConfigMock.getName() >> "test_column" // Provide a column name to prevent NPE + propertyConfigMock.getColumns() >> Arrays.asList(columnConfigMock) + + // Mocking other necessary properties of currentGrailsProp currentGrailsProp.getType() >> String.class currentGrailsProp.getName() >> "title" - propertyFromValueCreator.createProperty(_ as org.hibernate.mapping.Value, currentGrailsProp) >> new Property() - when: - propertyBinder.bindProperty(rootClass, mappings, "sessionFactory", currentGrailsProp) + // Capture the return value of bindProperty + def resultValue = propertyBinder.bindProperty(rootClass, mappings, "sessionFactory", currentGrailsProp) then: - 1 * simpleValueBinder.bindSimpleValue(currentGrailsProp, null, _ as SimpleValue, "") + // Assert that bindProperty returns a Value object + resultValue instanceof Value } - - }
