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 97f2ebe89b7fed92525b14377beb9787f5b87d71 Author: Walter Duque de Estrada <[email protected]> AuthorDate: Sun Feb 15 22:26:09 2026 -0600 Refactor GORM Hibernate 7 binding logic to centralize component updates - Create ComponentUpdater to encapsulate shared component-update and nullability logic. - Refactor ComponentBinder to autonomously create and return Component instances. - Inject ComponentUpdater into ComponentBinder, ComponentPropertyBinder, and CompositeIdBinder via GrailsDomainBinder. - Clean up redundant component update calls across binders. - Update test suite to reflect architectural changes and verify new component update logic. --- .../orm/hibernate/cfg/GrailsDomainBinder.java | 9 ++- .../cfg/domainbinding/binder/ComponentBinder.java | 10 ++- .../binder/ComponentPropertyBinder.java | 33 ++++----- .../cfg/domainbinding/binder/ComponentUpdater.java | 36 ++++++++++ .../domainbinding/binder/CompositeIdBinder.java | 12 +++- .../cfg/domainbinding/CollectionBinderSpec.groovy | 9 ++- .../CollectionSecondPassBinderSpec.groovy | 9 ++- .../cfg/domainbinding/ComponentBinderSpec.groovy | 9 ++- .../ComponentPropertyBinderSpec.groovy | 15 ++-- .../cfg/domainbinding/CompositeIdBinderSpec.groovy | 9 ++- .../domainbinding/GrailsPropertyBinderSpec.groovy | 9 ++- .../domainbinding/ListSecondPassBinderSpec.groovy | 9 ++- .../domainbinding/MapSecondPassBinderSpec.groovy | 9 ++- .../binder/ComponentUpdaterSpec.groovy | 80 ++++++++++++++++++++++ 14 files changed, 208 insertions(+), 50 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 fc34c716c7..13c914e79f 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 @@ -19,6 +19,7 @@ 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.ComponentBinder; import org.grails.orm.hibernate.cfg.domainbinding.binder.ComponentPropertyBinder; +import org.grails.orm.hibernate.cfg.domainbinding.binder.ComponentUpdater; import org.grails.orm.hibernate.cfg.domainbinding.binder.CompositeIdBinder; import org.grails.orm.hibernate.cfg.domainbinding.binder.EnumTypeBinder; import org.grails.orm.hibernate.cfg.domainbinding.util.NamingStrategyProvider; @@ -183,6 +184,7 @@ public class GrailsDomainBinder compositeIdentifierToManyToOneBinder, simpleValueColumnFetcher ); + ComponentUpdater componentUpdater = new ComponentUpdater(propertyFromValueCreator); ComponentPropertyBinder componentPropertyBinder = new ComponentPropertyBinder( metadataBuildingContext, namingStrategy, @@ -196,9 +198,10 @@ public class GrailsDomainBinder simpleValueBinder, oneToOneBinder, manyToOneBinder, - columnNameForPropertyAndPathFetcher + columnNameForPropertyAndPathFetcher, + componentUpdater ); - ComponentBinder componentBinder = new ComponentBinder(metadataBuildingContext, getMappingCacheHolder(), componentPropertyBinder); + ComponentBinder componentBinder = new ComponentBinder(metadataBuildingContext, getMappingCacheHolder(), componentPropertyBinder, componentUpdater); GrailsPropertyBinder grailsPropertyBinder = new GrailsPropertyBinder( metadataBuildingContext, namingStrategy, @@ -212,7 +215,7 @@ public class GrailsDomainBinder manyToOneBinder, propertyFromValueCreator ); - CompositeIdBinder compositeIdBinder = new CompositeIdBinder(metadataBuildingContext, componentPropertyBinder); + CompositeIdBinder compositeIdBinder = new CompositeIdBinder(metadataBuildingContext, componentPropertyBinder, componentUpdater); PropertyBinder propertyBinder = new PropertyBinder(); SimpleIdBinder simpleIdBinder = new SimpleIdBinder(metadataBuildingContext, namingStrategy, jdbcEnvironment, new BasicValueIdCreator(jdbcEnvironment), simpleValueBinder, propertyBinder); IdentityBinder identityBinder = new IdentityBinder(simpleIdBinder, compositeIdBinder); diff --git a/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/cfg/domainbinding/binder/ComponentBinder.java b/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/cfg/domainbinding/binder/ComponentBinder.java index b09fc227fe..0ef76618be 100644 --- a/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/cfg/domainbinding/binder/ComponentBinder.java +++ b/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/cfg/domainbinding/binder/ComponentBinder.java @@ -1,10 +1,15 @@ package org.grails.orm.hibernate.cfg.domainbinding.binder; +import java.util.Iterator; + import org.hibernate.boot.spi.InFlightMetadataCollector; import org.hibernate.boot.spi.MetadataBuildingContext; +import org.hibernate.mapping.Column; import org.hibernate.mapping.Component; import org.hibernate.mapping.PersistentClass; +import org.hibernate.mapping.Property; import org.hibernate.mapping.Table; +import org.hibernate.mapping.Value; import org.grails.datastore.mapping.model.config.GormProperties; import org.grails.orm.hibernate.cfg.GrailsHibernatePersistentEntity; @@ -12,6 +17,7 @@ import org.grails.orm.hibernate.cfg.GrailsHibernatePersistentProperty; import org.grails.orm.hibernate.cfg.GrailsHibernateUtil; import org.grails.orm.hibernate.cfg.MappingCacheHolder; import org.grails.orm.hibernate.cfg.domainbinding.hibernate.HibernateEmbeddedProperty; +import org.grails.orm.hibernate.cfg.domainbinding.util.PropertyFromValueCreator; import jakarta.annotation.Nonnull; @@ -20,11 +26,13 @@ public class ComponentBinder { private final MetadataBuildingContext metadataBuildingContext; private final MappingCacheHolder mappingCacheHolder; private final ComponentPropertyBinder componentPropertyBinder; + private final ComponentUpdater componentUpdater; - public ComponentBinder(MetadataBuildingContext metadataBuildingContext, MappingCacheHolder mappingCacheHolder, ComponentPropertyBinder componentPropertyBinder) { + public ComponentBinder(MetadataBuildingContext metadataBuildingContext, MappingCacheHolder mappingCacheHolder, ComponentPropertyBinder componentPropertyBinder, ComponentUpdater componentUpdater) { this.metadataBuildingContext = metadataBuildingContext; this.mappingCacheHolder = mappingCacheHolder; this.componentPropertyBinder = componentPropertyBinder; + this.componentUpdater = componentUpdater; } diff --git a/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/cfg/domainbinding/binder/ComponentPropertyBinder.java b/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/cfg/domainbinding/binder/ComponentPropertyBinder.java index 697b99179c..75a25f3118 100644 --- a/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/cfg/domainbinding/binder/ComponentPropertyBinder.java +++ b/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/cfg/domainbinding/binder/ComponentPropertyBinder.java @@ -52,6 +52,7 @@ public class ComponentPropertyBinder { private final ColumnNameForPropertyAndPathFetcher columnNameForPropertyAndPathFetcher; private final SimpleValueBinder simpleValueBinder; private final ComponentBinder componentBinder; + private final ComponentUpdater componentUpdater; public ComponentPropertyBinder(MetadataBuildingContext metadataBuildingContext, PersistentEntityNamingStrategy namingStrategy, @@ -66,7 +67,8 @@ public class ComponentPropertyBinder { new SimpleValueBinder(namingStrategy, jdbcEnvironment), new OneToOneBinder(namingStrategy, jdbcEnvironment), new ManyToOneBinder(namingStrategy, jdbcEnvironment), - new ColumnNameForPropertyAndPathFetcher(namingStrategy, new DefaultColumnNameFetcher(namingStrategy), new BackticksRemover())); + new ColumnNameForPropertyAndPathFetcher(namingStrategy, new DefaultColumnNameFetcher(namingStrategy), new BackticksRemover()), + new ComponentUpdater(propertyFromValueCreator)); } public ComponentPropertyBinder(MetadataBuildingContext metadataBuildingContext, @@ -81,7 +83,8 @@ public class ComponentPropertyBinder { SimpleValueBinder simpleValueBinder, OneToOneBinder oneToOneBinder, ManyToOneBinder manyToOneBinder, - ColumnNameForPropertyAndPathFetcher columnNameForPropertyAndPathFetcher) { + ColumnNameForPropertyAndPathFetcher columnNameForPropertyAndPathFetcher, + ComponentUpdater componentUpdater) { this.metadataBuildingContext = metadataBuildingContext; this.namingStrategy = namingStrategy; this.jdbcEnvironment = jdbcEnvironment; @@ -90,22 +93,23 @@ public class ComponentPropertyBinder { this.enumTypeBinder = enumTypeBinder; this.collectionBinder = collectionBinder; this.propertyFromValueCreator = propertyFromValueCreator; - this.componentBinder = componentBinder != null ? componentBinder : new ComponentBinder(metadataBuildingContext, mappingCacheHolder, this); + this.componentBinder = componentBinder != null ? componentBinder : new ComponentBinder(metadataBuildingContext, mappingCacheHolder, this, componentUpdater); this.simpleValueBinder = simpleValueBinder; this.oneToOneBinder = oneToOneBinder; this.manyToOneBinder = manyToOneBinder; this.columnNameForPropertyAndPathFetcher = columnNameForPropertyAndPathFetcher; + this.componentUpdater = componentUpdater; } - public void bindComponentProperty(Component component, - GrailsHibernatePersistentProperty componentProperty, + public Value bindComponentProperty(Component component, + GrailsHibernatePersistentProperty componentProperty, GrailsHibernatePersistentProperty currentGrailsProp, - PersistentClass persistentClass, + PersistentClass persistentClass, String path, - Table table, - @Nonnull InFlightMetadataCollector mappings) { + Table table, + @Nonnull InFlightMetadataCollector mappings) { Value value; // see if it's a collection type CollectionType collectionType = collectionHolder.get(currentGrailsProp.getType()); @@ -153,17 +157,8 @@ public class ComponentPropertyBinder { this.simpleValueBinder.bindSimpleValue(currentGrailsProp, componentProperty, (SimpleValue) value, path); } } - - Property persistentProperty = propertyFromValueCreator.createProperty(value, currentGrailsProp); - component.addProperty(persistentProperty); - if (componentProperty != null && componentProperty.getOwner() instanceof GrailsHibernatePersistentEntity ghpe && ghpe.isComponentPropertyNullable(componentProperty)) { - final Iterator<?> columnIterator = value.getColumns().iterator(); - while (columnIterator.hasNext()) { - Column c = (Column) columnIterator.next(); - c.setNullable(true); - } - } + componentUpdater.updateComponent(component, componentProperty, currentGrailsProp, value); + return value; } - } diff --git a/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/cfg/domainbinding/binder/ComponentUpdater.java b/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/cfg/domainbinding/binder/ComponentUpdater.java new file mode 100644 index 0000000000..8d25a0842d --- /dev/null +++ b/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/cfg/domainbinding/binder/ComponentUpdater.java @@ -0,0 +1,36 @@ +package org.grails.orm.hibernate.cfg.domainbinding.binder; + +import java.util.Iterator; + +import org.hibernate.mapping.Column; +import org.hibernate.mapping.Component; +import org.hibernate.mapping.Property; +import org.hibernate.mapping.Value; + +import org.grails.orm.hibernate.cfg.GrailsHibernatePersistentEntity; +import org.grails.orm.hibernate.cfg.GrailsHibernatePersistentProperty; +import org.grails.orm.hibernate.cfg.domainbinding.util.PropertyFromValueCreator; + +public class ComponentUpdater { + + private final PropertyFromValueCreator propertyFromValueCreator; + + public ComponentUpdater(PropertyFromValueCreator propertyFromValueCreator) { + this.propertyFromValueCreator = propertyFromValueCreator; + } + + public void updateComponent(Component component, + GrailsHibernatePersistentProperty componentProperty, + GrailsHibernatePersistentProperty currentGrailsProp, + Value value) { + Property persistentProperty = propertyFromValueCreator.createProperty(value, currentGrailsProp); + component.addProperty(persistentProperty); + if (componentProperty != null && componentProperty.getOwner() instanceof GrailsHibernatePersistentEntity ghpe && ghpe.isComponentPropertyNullable(componentProperty)) { + final Iterator<?> columnIterator = value.getColumns().iterator(); + while (columnIterator.hasNext()) { + Column c = (Column) columnIterator.next(); + c.setNullable(true); + } + } + } +} 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 048715a1ad..3426fe5440 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 @@ -1,15 +1,21 @@ package org.grails.orm.hibernate.cfg.domainbinding.binder; +import java.util.Iterator; + import org.hibernate.MappingException; import org.hibernate.boot.spi.InFlightMetadataCollector; import org.hibernate.boot.spi.MetadataBuildingContext; +import org.hibernate.mapping.Column; import org.hibernate.mapping.Component; +import org.hibernate.mapping.Property; import org.hibernate.mapping.RootClass; +import org.hibernate.mapping.Value; import org.grails.orm.hibernate.cfg.CompositeIdentity; import org.grails.orm.hibernate.cfg.GrailsHibernatePersistentEntity; import org.grails.orm.hibernate.cfg.GrailsHibernatePersistentProperty; import org.grails.orm.hibernate.cfg.GrailsHibernateUtil; +import org.grails.orm.hibernate.cfg.domainbinding.util.PropertyFromValueCreator; import jakarta.annotation.Nonnull; @@ -17,10 +23,12 @@ public class CompositeIdBinder { private final MetadataBuildingContext metadataBuildingContext; private final ComponentPropertyBinder componentPropertyBinder; + private final ComponentUpdater componentUpdater; - public CompositeIdBinder(MetadataBuildingContext metadataBuildingContext, ComponentPropertyBinder componentPropertyBinder) { + public CompositeIdBinder(MetadataBuildingContext metadataBuildingContext, ComponentPropertyBinder componentPropertyBinder, ComponentUpdater componentUpdater) { this.metadataBuildingContext = metadataBuildingContext; this.componentPropertyBinder = componentPropertyBinder; + this.componentUpdater = componentUpdater; } @@ -61,7 +69,7 @@ public class CompositeIdBinder { "] is not a valid property!"); } - componentPropertyBinder.bindComponentProperty(id, identifierProp, property, root, "", root.getTable(), mappings); + componentPropertyBinder.bindComponentProperty(id, identifierProp, property, root, "", root.getTable(), mappings); } } } 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 2653cfd25a..cb1f99cfcb 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 @@ -36,6 +36,7 @@ import org.grails.orm.hibernate.cfg.domainbinding.collectionType.CollectionHolde import org.grails.orm.hibernate.cfg.domainbinding.util.PropertyFromValueCreator import org.grails.orm.hibernate.cfg.domainbinding.binder.ComponentBinder import org.grails.orm.hibernate.cfg.domainbinding.binder.ComponentPropertyBinder +import org.grails.orm.hibernate.cfg.domainbinding.binder.ComponentUpdater import org.grails.orm.hibernate.cfg.domainbinding.util.BasicValueIdCreator import org.grails.orm.hibernate.cfg.domainbinding.binder.ClassPropertiesBinder @@ -79,6 +80,7 @@ class CollectionBinderSpec extends HibernateGormDatastoreSpec { simpleValueColumnFetcher ) PropertyFromValueCreator propertyFromValueCreator = new PropertyFromValueCreator() + ComponentUpdater componentUpdater = new ComponentUpdater(propertyFromValueCreator) ComponentPropertyBinder componentPropertyBinder = new ComponentPropertyBinder( metadataBuildingContext, namingStrategy, @@ -92,9 +94,10 @@ class CollectionBinderSpec extends HibernateGormDatastoreSpec { simpleValueBinder, oneToOneBinder, manyToOneBinder, - columnNameForPropertyAndPathFetcher + columnNameForPropertyAndPathFetcher, + componentUpdater ) - ComponentBinder componentBinder = new ComponentBinder(metadataBuildingContext, binder.getMappingCacheHolder(), componentPropertyBinder) + ComponentBinder componentBinder = new ComponentBinder(metadataBuildingContext, binder.getMappingCacheHolder(), componentPropertyBinder, componentUpdater) GrailsPropertyBinder propertyBinder = new GrailsPropertyBinder( metadataBuildingContext, namingStrategy, @@ -108,7 +111,7 @@ class CollectionBinderSpec extends HibernateGormDatastoreSpec { manyToOneBinder, propertyFromValueCreator ) - CompositeIdBinder compositeIdBinder = new CompositeIdBinder(metadataBuildingContext, componentPropertyBinder) + CompositeIdBinder compositeIdBinder = new CompositeIdBinder(metadataBuildingContext, componentPropertyBinder, componentUpdater) 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 19e5e00eee..d9b5356afe 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 @@ -29,6 +29,7 @@ import org.grails.orm.hibernate.cfg.domainbinding.binder.OneToOneBinder import org.grails.orm.hibernate.cfg.domainbinding.binder.ClassBinder import org.grails.orm.hibernate.cfg.domainbinding.binder.ComponentBinder import org.grails.orm.hibernate.cfg.domainbinding.binder.ComponentPropertyBinder +import org.grails.orm.hibernate.cfg.domainbinding.binder.ComponentUpdater import org.grails.orm.hibernate.cfg.domainbinding.util.BasicValueIdCreator import org.grails.orm.hibernate.cfg.domainbinding.binder.GrailsPropertyBinder import org.grails.orm.hibernate.cfg.domainbinding.binder.IdentityBinder @@ -81,6 +82,7 @@ class CollectionSecondPassBinderSpec extends HibernateGormDatastoreSpec { simpleValueColumnFetcher ) PropertyFromValueCreator propertyFromValueCreator = new PropertyFromValueCreator() + ComponentUpdater componentUpdater = new ComponentUpdater(propertyFromValueCreator) ComponentPropertyBinder componentPropertyBinder = new ComponentPropertyBinder( metadataBuildingContext, namingStrategy, @@ -94,9 +96,10 @@ class CollectionSecondPassBinderSpec extends HibernateGormDatastoreSpec { simpleValueBinder, oneToOneBinder, manyToOneBinder, - columnNameForPropertyAndPathFetcher + columnNameForPropertyAndPathFetcher, + componentUpdater ) - ComponentBinder componentBinder = new ComponentBinder(metadataBuildingContext, binder.getMappingCacheHolder(), componentPropertyBinder) + ComponentBinder componentBinder = new ComponentBinder(metadataBuildingContext, binder.getMappingCacheHolder(), componentPropertyBinder, componentUpdater) GrailsPropertyBinder propertyBinder = new GrailsPropertyBinder( metadataBuildingContext, namingStrategy, @@ -110,7 +113,7 @@ class CollectionSecondPassBinderSpec extends HibernateGormDatastoreSpec { manyToOneBinder, propertyFromValueCreator ) - CompositeIdBinder compositeIdBinder = new CompositeIdBinder(metadataBuildingContext, componentPropertyBinder) + CompositeIdBinder compositeIdBinder = new CompositeIdBinder(metadataBuildingContext, componentPropertyBinder, componentUpdater) 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/ComponentBinderSpec.groovy b/grails-data-hibernate7/core/src/test/groovy/org/grails/orm/hibernate/cfg/domainbinding/ComponentBinderSpec.groovy index dd8d19890f..a35d653d04 100644 --- a/grails-data-hibernate7/core/src/test/groovy/org/grails/orm/hibernate/cfg/domainbinding/ComponentBinderSpec.groovy +++ b/grails-data-hibernate7/core/src/test/groovy/org/grails/orm/hibernate/cfg/domainbinding/ComponentBinderSpec.groovy @@ -12,17 +12,21 @@ import spock.lang.Subject import org.grails.orm.hibernate.cfg.domainbinding.binder.ComponentBinder import org.grails.orm.hibernate.cfg.domainbinding.binder.ComponentPropertyBinder +import org.grails.orm.hibernate.cfg.domainbinding.binder.ComponentUpdater +import org.hibernate.mapping.Value +import org.hibernate.mapping.Table class ComponentBinderSpec extends HibernateGormDatastoreSpec { MappingCacheHolder mappingCacheHolder = Mock(MappingCacheHolder) ComponentPropertyBinder componentPropertyBinder = Mock(ComponentPropertyBinder) + ComponentUpdater componentUpdater = Mock(ComponentUpdater) @Subject ComponentBinder binder def setup() { - binder = new ComponentBinder(getGrailsDomainBinder().getMetadataBuildingContext(), mappingCacheHolder, componentPropertyBinder) + binder = new ComponentBinder(getGrailsDomainBinder().getMetadataBuildingContext(), mappingCacheHolder, componentPropertyBinder, componentUpdater) } def "should bind component and its properties"() { @@ -30,6 +34,7 @@ class ComponentBinderSpec extends HibernateGormDatastoreSpec { def metadataBuildingContext = getGrailsDomainBinder().getMetadataBuildingContext() def root = new RootClass(metadataBuildingContext) root.setEntityName("MyEntity") + root.setTable(new Table("my_entity")) def embeddedProp = GroovyMock(HibernateEmbeddedProperty) def associatedEntity = GroovyMock(GrailsHibernatePersistentEntity) @@ -57,7 +62,7 @@ class ComponentBinderSpec extends HibernateGormDatastoreSpec { component.getComponentClassName() == Address.name component.getRoleName() == Address.name + ".address" 1 * mappingCacheHolder.cacheMapping(associatedEntity) - 1 * componentPropertyBinder.bindComponentProperty(_, _, _, _, _, _, _) + 1 * componentPropertyBinder.bindComponentProperty(_ as Component, embeddedProp, prop1, root, "address", _ as Table, mappings) >> Mock(Value) } static class MyEntity {} diff --git a/grails-data-hibernate7/core/src/test/groovy/org/grails/orm/hibernate/cfg/domainbinding/ComponentPropertyBinderSpec.groovy b/grails-data-hibernate7/core/src/test/groovy/org/grails/orm/hibernate/cfg/domainbinding/ComponentPropertyBinderSpec.groovy index 0a4df79439..8ed981ff28 100644 --- a/grails-data-hibernate7/core/src/test/groovy/org/grails/orm/hibernate/cfg/domainbinding/ComponentPropertyBinderSpec.groovy +++ b/grails-data-hibernate7/core/src/test/groovy/org/grails/orm/hibernate/cfg/domainbinding/ComponentPropertyBinderSpec.groovy @@ -16,6 +16,7 @@ import org.grails.orm.hibernate.cfg.domainbinding.hibernate.HibernateOneToOnePro import org.grails.orm.hibernate.cfg.domainbinding.binder.CollectionBinder import org.grails.orm.hibernate.cfg.domainbinding.binder.ComponentBinder import org.grails.orm.hibernate.cfg.domainbinding.binder.ComponentPropertyBinder +import org.grails.orm.hibernate.cfg.domainbinding.binder.ComponentUpdater import org.grails.orm.hibernate.cfg.domainbinding.binder.EnumTypeBinder import org.grails.orm.hibernate.cfg.domainbinding.binder.OneToOneBinder import org.grails.orm.hibernate.cfg.domainbinding.binder.ManyToOneBinder @@ -58,6 +59,7 @@ class ComponentPropertyBinderSpec extends HibernateGormDatastoreSpec { OneToOneBinder oneToOneBinder = Mock(OneToOneBinder) ManyToOneBinder manyToOneBinder = Mock(ManyToOneBinder) ColumnNameForPropertyAndPathFetcher columnNameFetcher = Mock(ColumnNameForPropertyAndPathFetcher) + ComponentUpdater componentUpdater @Subject ComponentPropertyBinder binder @@ -66,6 +68,7 @@ class ComponentPropertyBinderSpec extends HibernateGormDatastoreSpec { def setup() { def jdbcEnvironment = Mock(org.hibernate.engine.jdbc.env.spi.JdbcEnvironment) + componentUpdater = new ComponentUpdater(propertyFromValueCreator) binder = new ComponentPropertyBinder( getGrailsDomainBinder().getMetadataBuildingContext(), @@ -80,7 +83,8 @@ class ComponentPropertyBinderSpec extends HibernateGormDatastoreSpec { mockSimpleValueBinder, oneToOneBinder, manyToOneBinder, - columnNameFetcher + columnNameFetcher, + componentUpdater ) } @@ -124,7 +128,7 @@ class ComponentPropertyBinderSpec extends HibernateGormDatastoreSpec { then: 1 * mockSimpleValueBinder.bindSimpleValue(currentGrailsProp, componentProperty, _ as BasicValue, "address") - component.getProperty("street") == hibernateProperty + 1 * propertyFromValueCreator.createProperty(_ as BasicValue, currentGrailsProp) >> hibernateProperty } def "should bind many-to-one property"() { @@ -158,8 +162,8 @@ class ComponentPropertyBinderSpec extends HibernateGormDatastoreSpec { binder.bindComponentProperty(component, componentProperty, currentGrailsProp, root, "address", table, mappings) then: + 1 * manyToOneBinder.bindManyToOne(currentGrailsProp, _ as HibernateManyToOne, "address") 1 * propertyFromValueCreator.createProperty(_ as HibernateManyToOne, currentGrailsProp) >> hibernateProperty - component.getProperty("owner") == hibernateProperty } def "should bind one-to-one property"() { @@ -197,8 +201,8 @@ class ComponentPropertyBinderSpec extends HibernateGormDatastoreSpec { binder.bindComponentProperty(component, componentProperty, currentGrailsProp, root, "address", table, mappings) then: + 1 * oneToOneBinder.bindOneToOne(currentGrailsProp, _ as HibernateOneToOne, "address") 1 * propertyFromValueCreator.createProperty(_ as HibernateOneToOne, currentGrailsProp) >> hibernateProperty - component.getProperty("detail") == hibernateProperty } def "should bind enum property"() { @@ -231,6 +235,7 @@ class ComponentPropertyBinderSpec extends HibernateGormDatastoreSpec { then: 1 * enumTypeBinder.bindEnumType(currentGrailsProp, MyEnum, _ as BasicValue, "address_type_col") + 1 * propertyFromValueCreator.createProperty(_ as BasicValue, currentGrailsProp) >> hibernateProperty } def "should set columns to nullable when component property is nullable"() { @@ -267,7 +272,7 @@ class ComponentPropertyBinderSpec extends HibernateGormDatastoreSpec { _ as BasicValue, "address" ) - 1 * ownerEntity.isComponentPropertyNullable(componentProperty) >> true + 1 * propertyFromValueCreator.createProperty(_ as BasicValue, currentGrailsProp) >> hibernateProperty } enum MyEnum { VAL } 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 cc66523f39..b6936d735e 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 @@ -13,16 +13,19 @@ import spock.lang.Subject import org.grails.orm.hibernate.cfg.domainbinding.binder.ComponentPropertyBinder import org.grails.orm.hibernate.cfg.domainbinding.binder.CompositeIdBinder +import org.grails.orm.hibernate.cfg.domainbinding.binder.ComponentUpdater +import org.hibernate.mapping.Value class CompositeIdBinderSpec extends HibernateGormDatastoreSpec { def componentPropertyBinder = Mock(ComponentPropertyBinder) + def componentUpdater = Mock(ComponentUpdater) @Subject CompositeIdBinder binder def setup() { - binder = new CompositeIdBinder(getGrailsDomainBinder().getMetadataBuildingContext(), componentPropertyBinder) + binder = new CompositeIdBinder(getGrailsDomainBinder().getMetadataBuildingContext(), componentPropertyBinder, componentUpdater) } def "should bind composite id using property names from CompositeIdentity"() { @@ -53,7 +56,7 @@ class CompositeIdBinderSpec extends HibernateGormDatastoreSpec { root.getIdentifier() instanceof Component root.getIdentifierMapper() instanceof Component root.hasEmbeddedIdentifier() - 2 * componentPropertyBinder.bindComponentProperty(_ as Component, identifierProp, _ as PersistentProperty, root, "", table, mappings) + 2 * componentPropertyBinder.bindComponentProperty(_ as Component, identifierProp, _ as PersistentProperty, root, "", table, mappings) >> Mock(Value) } def "should fallback to domainClass composite identity when CompositeIdentity is null"() { @@ -77,7 +80,7 @@ class CompositeIdBinderSpec extends HibernateGormDatastoreSpec { binder.bindCompositeId(domainClass, root, null, mappings) then: - 1 * componentPropertyBinder.bindComponentProperty(_ as Component, identifierProp, prop1, root, "", table, mappings) + 1 * componentPropertyBinder.bindComponentProperty(_ as Component, identifierProp, prop1, root, "", table, mappings) >> Mock(Value) } def "should throw MappingException if no composite properties found"() { 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 e6855682cb..12933320f6 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 @@ -15,6 +15,7 @@ import org.grails.orm.hibernate.cfg.domainbinding.binder.CollectionBinder import org.grails.orm.hibernate.cfg.domainbinding.binder.ClassBinder import org.grails.orm.hibernate.cfg.domainbinding.binder.ComponentBinder import org.grails.orm.hibernate.cfg.domainbinding.binder.ComponentPropertyBinder +import org.grails.orm.hibernate.cfg.domainbinding.binder.ComponentUpdater import org.grails.orm.hibernate.cfg.domainbinding.binder.EnumTypeBinder import org.grails.orm.hibernate.cfg.domainbinding.binder.GrailsPropertyBinder import org.grails.orm.hibernate.cfg.domainbinding.binder.ManyToOneBinder @@ -83,6 +84,7 @@ class GrailsPropertyBinderSpec extends HibernateGormDatastoreSpec { simpleValueColumnFetcher ) PropertyFromValueCreator propertyFromValueCreator = new PropertyFromValueCreator() + ComponentUpdater componentUpdater = new ComponentUpdater(propertyFromValueCreator) ComponentPropertyBinder componentPropertyBinder = new ComponentPropertyBinder( metadataBuildingContext, namingStrategy, @@ -96,9 +98,10 @@ class GrailsPropertyBinderSpec extends HibernateGormDatastoreSpec { simpleValueBinder, oneToOneBinder, manyToOneBinder, - columnNameForPropertyAndPathFetcher + columnNameForPropertyAndPathFetcher, + componentUpdater ) - ComponentBinder componentBinder = new ComponentBinder(metadataBuildingContext, binder.getMappingCacheHolder(), componentPropertyBinder) + ComponentBinder componentBinder = new ComponentBinder(metadataBuildingContext, binder.getMappingCacheHolder(), componentPropertyBinder, componentUpdater) GrailsPropertyBinder propertyBinder = new GrailsPropertyBinder( metadataBuildingContext, namingStrategy, @@ -112,7 +115,7 @@ class GrailsPropertyBinderSpec extends HibernateGormDatastoreSpec { manyToOneBinder, propertyFromValueCreator ) - CompositeIdBinder compositeIdBinder = new CompositeIdBinder(metadataBuildingContext, componentPropertyBinder) + CompositeIdBinder compositeIdBinder = new CompositeIdBinder(metadataBuildingContext, componentPropertyBinder, componentUpdater) 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/ListSecondPassBinderSpec.groovy b/grails-data-hibernate7/core/src/test/groovy/org/grails/orm/hibernate/cfg/domainbinding/ListSecondPassBinderSpec.groovy index 3dfcbbcb13..36fe049ac2 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 @@ -31,6 +31,7 @@ import org.grails.orm.hibernate.cfg.domainbinding.binder.OneToOneBinder import org.grails.orm.hibernate.cfg.domainbinding.binder.ClassBinder import org.grails.orm.hibernate.cfg.domainbinding.binder.ComponentBinder import org.grails.orm.hibernate.cfg.domainbinding.binder.ComponentPropertyBinder +import org.grails.orm.hibernate.cfg.domainbinding.binder.ComponentUpdater import org.grails.orm.hibernate.cfg.domainbinding.util.BasicValueIdCreator import org.grails.orm.hibernate.cfg.domainbinding.binder.GrailsPropertyBinder import org.grails.orm.hibernate.cfg.domainbinding.binder.IdentityBinder @@ -83,6 +84,7 @@ class ListSecondPassBinderSpec extends HibernateGormDatastoreSpec { simpleValueColumnFetcher ) PropertyFromValueCreator propertyFromValueCreator = new PropertyFromValueCreator() + ComponentUpdater componentUpdater = new ComponentUpdater(propertyFromValueCreator) ComponentPropertyBinder componentPropertyBinder = new ComponentPropertyBinder( metadataBuildingContext, namingStrategy, @@ -96,9 +98,10 @@ class ListSecondPassBinderSpec extends HibernateGormDatastoreSpec { simpleValueBinder, oneToOneBinder, manyToOneBinder, - columnNameForPropertyAndPathFetcher + columnNameForPropertyAndPathFetcher, + componentUpdater ) - ComponentBinder componentBinder = new ComponentBinder(metadataBuildingContext, binder.getMappingCacheHolder(), componentPropertyBinder) + ComponentBinder componentBinder = new ComponentBinder(metadataBuildingContext, binder.getMappingCacheHolder(), componentPropertyBinder, componentUpdater) GrailsPropertyBinder propertyBinder = new GrailsPropertyBinder( metadataBuildingContext, namingStrategy, @@ -112,7 +115,7 @@ class ListSecondPassBinderSpec extends HibernateGormDatastoreSpec { manyToOneBinder, propertyFromValueCreator ) - CompositeIdBinder compositeIdBinder = new CompositeIdBinder(metadataBuildingContext, componentPropertyBinder) + CompositeIdBinder compositeIdBinder = new CompositeIdBinder(metadataBuildingContext, componentPropertyBinder, componentUpdater) 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 adbb5f0e93..44736dc535 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 @@ -31,6 +31,7 @@ import org.grails.orm.hibernate.cfg.domainbinding.binder.OneToOneBinder import org.grails.orm.hibernate.cfg.domainbinding.binder.ClassBinder import org.grails.orm.hibernate.cfg.domainbinding.binder.ComponentBinder import org.grails.orm.hibernate.cfg.domainbinding.binder.ComponentPropertyBinder +import org.grails.orm.hibernate.cfg.domainbinding.binder.ComponentUpdater import org.grails.orm.hibernate.cfg.domainbinding.util.BasicValueIdCreator import org.grails.orm.hibernate.cfg.domainbinding.binder.GrailsPropertyBinder import org.grails.orm.hibernate.cfg.domainbinding.binder.IdentityBinder @@ -83,6 +84,7 @@ class MapSecondPassBinderSpec extends HibernateGormDatastoreSpec { simpleValueColumnFetcher ) PropertyFromValueCreator propertyFromValueCreator = new PropertyFromValueCreator() + ComponentUpdater componentUpdater = new ComponentUpdater(propertyFromValueCreator) ComponentPropertyBinder componentPropertyBinder = new ComponentPropertyBinder( metadataBuildingContext, namingStrategy, @@ -96,9 +98,10 @@ class MapSecondPassBinderSpec extends HibernateGormDatastoreSpec { simpleValueBinder, oneToOneBinder, manyToOneBinder, - columnNameForPropertyAndPathFetcher + columnNameForPropertyAndPathFetcher, + componentUpdater ) - ComponentBinder componentBinder = new ComponentBinder(metadataBuildingContext, binder.getMappingCacheHolder(), componentPropertyBinder) + ComponentBinder componentBinder = new ComponentBinder(metadataBuildingContext, binder.getMappingCacheHolder(), componentPropertyBinder, componentUpdater) GrailsPropertyBinder propertyBinder = new GrailsPropertyBinder( metadataBuildingContext, namingStrategy, @@ -112,7 +115,7 @@ class MapSecondPassBinderSpec extends HibernateGormDatastoreSpec { manyToOneBinder, propertyFromValueCreator ) - CompositeIdBinder compositeIdBinder = new CompositeIdBinder(metadataBuildingContext, componentPropertyBinder) + CompositeIdBinder compositeIdBinder = new CompositeIdBinder(metadataBuildingContext, componentPropertyBinder, componentUpdater) 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/binder/ComponentUpdaterSpec.groovy b/grails-data-hibernate7/core/src/test/groovy/org/grails/orm/hibernate/cfg/domainbinding/binder/ComponentUpdaterSpec.groovy new file mode 100644 index 0000000000..1a940b8fba --- /dev/null +++ b/grails-data-hibernate7/core/src/test/groovy/org/grails/orm/hibernate/cfg/domainbinding/binder/ComponentUpdaterSpec.groovy @@ -0,0 +1,80 @@ +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.domainbinding.util.PropertyFromValueCreator +import org.hibernate.mapping.BasicValue +import org.hibernate.mapping.Column +import org.hibernate.mapping.Component +import org.hibernate.mapping.Property +import org.hibernate.mapping.RootClass +import spock.lang.Subject + +class ComponentUpdaterSpec extends HibernateGormDatastoreSpec { + + def propertyFromValueCreator = Mock(PropertyFromValueCreator) + + @Subject + ComponentUpdater updater + + def setup() { + updater = new ComponentUpdater(propertyFromValueCreator) + } + + def "should add property to component and set columns nullable if component property is nullable"() { + given: + def metadataBuildingContext = getGrailsDomainBinder().getMetadataBuildingContext() + def root = new RootClass(metadataBuildingContext) + def component = new Component(metadataBuildingContext, root) + + def componentProperty = Mock(GrailsHibernatePersistentProperty) + def currentGrailsProp = Mock(GrailsHibernatePersistentProperty) + def value = new BasicValue(metadataBuildingContext, root.getTable()) + def column = new Column("test_col") + value.addColumn(column) + + def hibernateProperty = new Property() + hibernateProperty.setName("testProp") + + def ownerEntity = Mock(GrailsHibernatePersistentEntity) + componentProperty.getOwner() >> ownerEntity + ownerEntity.isComponentPropertyNullable(componentProperty) >> true + + when: + updater.updateComponent(component, componentProperty, currentGrailsProp, value) + + then: + 1 * propertyFromValueCreator.createProperty(value, currentGrailsProp) >> hibernateProperty + component.getProperty("testProp") == hibernateProperty + column.isNullable() + } + + def "should not set columns nullable if component property is not nullable"() { + given: + def metadataBuildingContext = getGrailsDomainBinder().getMetadataBuildingContext() + def root = new RootClass(metadataBuildingContext) + def component = new Component(metadataBuildingContext, root) + + def componentProperty = Mock(GrailsHibernatePersistentProperty) + def currentGrailsProp = Mock(GrailsHibernatePersistentProperty) + def value = new BasicValue(metadataBuildingContext, root.getTable()) + def column = new Column("test_col") + column.setNullable(false) + value.addColumn(column) + + def hibernateProperty = new Property() + hibernateProperty.setName("testProp") + + def ownerEntity = Mock(GrailsHibernatePersistentEntity) + componentProperty.getOwner() >> ownerEntity + ownerEntity.isComponentPropertyNullable(componentProperty) >> false + + when: + updater.updateComponent(component, componentProperty, currentGrailsProp, value) + + then: + 1 * propertyFromValueCreator.createProperty(value, currentGrailsProp) >> hibernateProperty + !column.isNullable() + } +}
