This is an automated email from the ASF dual-hosted git repository. borinquenkid pushed a commit to branch 8.0.x-hibernate7-dev in repository https://gitbox.apache.org/repos/asf/grails-core.git
commit 085c93168ffd26749ea91ae5076875d0ac42ebe4 Author: Walter Duque de Estrada <[email protected]> AuthorDate: Sat Mar 14 14:03:05 2026 -0500 hibernate 7: first step in encapsulating Table inside of HibernatePersistentEntity --- .../binder/ClassPropertiesBinder.java | 5 +- .../cfg/domainbinding/binder/ComponentBinder.java | 12 +- .../domainbinding/binder/CompositeIdBinder.java | 20 +-- .../cfg/domainbinding/ComponentBinderSpec.groovy | 144 +++++---------------- .../cfg/domainbinding/CompositeIdBinderSpec.groovy | 46 +++---- 5 files changed, 73 insertions(+), 154 deletions(-) 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 index 5d753eddce..937de8ae43 100644 --- 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 @@ -61,9 +61,8 @@ public class ClassPropertiesBinder { public void bindClassProperties(HibernatePersistentEntity hibernatePersistentEntity) { PersistentClass persistentClass = hibernatePersistentEntity.getPersistentClass(); - @Nonnull Table table = getTable(persistentClass); - table.setComment(hibernatePersistentEntity.getComment()); - + getTable(persistentClass).setComment(hibernatePersistentEntity.getComment()); + Table table = hibernatePersistentEntity.getPersistentClass().getTable(); for (HibernatePersistentProperty currentGrailsProp : hibernatePersistentEntity.getPersistentPropertiesToBind()) { Value value = grailsPropertyBinder.bindProperty( persistentClass, table, GrailsDomainBinder.EMPTY_PATH, null, currentGrailsProp); 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 0a81e9a397..8973546818 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 @@ -60,18 +60,20 @@ public class ComponentBinder { component.setRoleName(role); component.setComponentClassName(type.getName()); - GrailsHibernatePersistentEntity domainClass = + GrailsHibernatePersistentEntity associatedEntity = (GrailsHibernatePersistentEntity) embeddedProperty.getAssociatedEntity(); - mappingCacheHolder.cacheMapping(domainClass); + mappingCacheHolder.cacheMapping(associatedEntity); + - Table table = component.getOwner().getTable(); PersistentClass persistentClass = component.getOwner(); + associatedEntity.setPersistentClass(persistentClass); + Table table = associatedEntity.getPersistentClass().getTable(); String currentPath = path.isEmpty() ? embeddedProperty.getName() : path + "." + embeddedProperty.getName(); Class<?> propertyType = embeddedProperty.getOwner().getJavaClass(); - domainClass.getHibernateParentProperty(propertyType).ifPresent(p -> component.setParentProperty(p.getName())); + associatedEntity.getHibernateParentProperty(propertyType).ifPresent(p -> component.setParentProperty(p.getName())); - for (HibernatePersistentProperty peerProperty : domainClass.getHibernatePersistentProperties(propertyType)) { + for (HibernatePersistentProperty peerProperty : associatedEntity.getHibernatePersistentProperties(propertyType)) { var value = grailsPropertyBinder.bindProperty( persistentClass, table, currentPath, embeddedProperty, peerProperty); componentUpdater.updateComponent(component, embeddedProperty, peerProperty, value); 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 c9e0ee8cd7..1c14f6776b 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 @@ -23,7 +23,9 @@ import jakarta.annotation.Nonnull; import org.hibernate.MappingException; import org.hibernate.boot.spi.MetadataBuildingContext; import org.hibernate.mapping.Component; +import org.hibernate.mapping.PersistentClass; import org.hibernate.mapping.RootClass; +import org.hibernate.mapping.Table; import org.grails.orm.hibernate.cfg.CompositeIdentity; import org.grails.orm.hibernate.cfg.GrailsHibernateUtil; @@ -48,13 +50,14 @@ public class CompositeIdBinder { } public void bindCompositeId( - @Nonnull HibernatePersistentEntity domainClass, RootClass root, CompositeIdentity compositeIdentity) { + @Nonnull HibernatePersistentEntity hibernatePersistentEntity, RootClass root, CompositeIdentity compositeIdentity) { + hibernatePersistentEntity.setPersistentClass(root); Component id = new Component(metadataBuildingContext, root); id.setNullValue("undefined"); root.setIdentifier(id); root.setIdentifierMapper(id); root.setEmbeddedIdentifier(true); - id.setComponentClassName(domainClass.getName()); + id.setComponentClassName(hibernatePersistentEntity.getName()); id.setKey(true); id.setEmbedded(true); @@ -63,16 +66,17 @@ public class CompositeIdBinder { id.setRoleName(path); HibernatePersistentProperty[] composite = compositeIdentity != null - ? compositeIdentity.getHibernateProperties(domainClass) - : domainClass.getCompositeIdentity(); + ? compositeIdentity.getHibernateProperties(hibernatePersistentEntity) + : hibernatePersistentEntity.getCompositeIdentity(); if (composite == null || composite.length == 0) { - throw new MappingException("No composite identifier properties found for class [" + domainClass.getName() + "]"); + throw new MappingException("No composite identifier properties found for class [" + hibernatePersistentEntity.getName() + "]"); } - - HibernatePersistentProperty identifierProp = domainClass.getIdentity(); + PersistentClass persistentClass = hibernatePersistentEntity.getPersistentClass(); + Table table = persistentClass.getTable(); + HibernatePersistentProperty identifierProp = hibernatePersistentEntity.getIdentity(); for (HibernatePersistentProperty property : composite) { - var value = grailsPropertyBinder.bindProperty(root, root.getTable(), "", identifierProp, property); + var value = grailsPropertyBinder.bindProperty(persistentClass, table, "", identifierProp, property); componentUpdater.updateComponent(id, identifierProp, property, value); } } 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 13f24d125f..a58e9cfd26 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 @@ -16,8 +16,6 @@ import org.grails.orm.hibernate.cfg.domainbinding.hibernate.HibernateOneToOnePro import org.grails.orm.hibernate.cfg.domainbinding.hibernate.HibernateSimpleProperty import org.grails.orm.hibernate.cfg.domainbinding.binder.ComponentBinder import org.grails.orm.hibernate.cfg.domainbinding.binder.ComponentUpdater -import org.grails.orm.hibernate.cfg.domainbinding.collectionType.CollectionHolder - import org.hibernate.mapping.BasicValue import org.hibernate.mapping.Component import org.hibernate.mapping.RootClass @@ -25,49 +23,10 @@ import org.hibernate.mapping.Table import org.hibernate.mapping.Value import spock.lang.Subject -import org.grails.orm.hibernate.cfg.domainbinding.util.PropertyFromValueCreator - class ComponentBinderSpec extends HibernateGormDatastoreSpec { - abstract static class TestManyToOne extends HibernateManyToOneProperty { - TestManyToOne(PersistentEntity owner, MappingContext context, java.beans.PropertyDescriptor descriptor) { - super(owner, context, descriptor); - } - } - - abstract static class TestOneToOne extends HibernateOneToOneProperty { - TestOneToOne(PersistentEntity owner, MappingContext context, java.beans.PropertyDescriptor descriptor) { - super(owner, context, descriptor); - } - } - - abstract static class TestOneToMany extends org.grails.orm.hibernate.cfg.domainbinding.hibernate.HibernateOneToManyProperty { - TestOneToMany(PersistentEntity owner, MappingContext context, java.beans.PropertyDescriptor descriptor) { - super(owner, context, descriptor); - } - } - - abstract static class TestEmbedded extends HibernateEmbeddedProperty { - TestEmbedded(PersistentEntity owner, MappingContext context, java.beans.PropertyDescriptor descriptor) { - super(owner, context, descriptor); - } - } - - abstract static class TestBasic extends HibernateBasicProperty { - TestBasic(GrailsHibernatePersistentEntity owner, MappingContext context, java.beans.PropertyDescriptor descriptor) { - super(owner, context, descriptor); - } - } - - abstract static class TestSimple extends HibernateSimpleProperty { - TestSimple(PersistentEntity owner, MappingContext context, java.beans.PropertyDescriptor descriptor) { - super(owner, context, descriptor); - } - } - + // Mock Collaborators MappingCacheHolder mappingCacheHolder = Mock(MappingCacheHolder) - CollectionHolder collectionHolder - PropertyFromValueCreator propertyFromValueCreator = Mock(PropertyFromValueCreator) ComponentUpdater componentUpdater = Mock(ComponentUpdater) org.grails.orm.hibernate.cfg.domainbinding.binder.GrailsPropertyBinder grailsPropertyBinder = Mock(org.grails.orm.hibernate.cfg.domainbinding.binder.GrailsPropertyBinder) @@ -76,55 +35,30 @@ class ComponentBinderSpec extends HibernateGormDatastoreSpec { def setup() { def metadataBuildingContext = getGrailsDomainBinder().getMetadataBuildingContext() - binder = new ComponentBinder( - metadataBuildingContext, - mappingCacheHolder, - componentUpdater - ) + binder = new ComponentBinder(metadataBuildingContext, mappingCacheHolder, componentUpdater) binder.setGrailsPropertyBinder(grailsPropertyBinder) } - private void setupProperty(PersistentProperty prop, String name, Mapping mapping, PersistentEntity owner) { - prop.getName() >> name - _ * prop.getOwner() >> owner - if (prop instanceof HibernatePersistentProperty) { - _ * ((HibernatePersistentProperty)prop).getHibernateOwner() >> owner - } - def config = new PropertyConfig() - mapping.getColumns().put(name, config) - prop.getMappedForm() >> config - } - def "should bind component and its properties"() { given: def metadataBuildingContext = getGrailsDomainBinder().getMetadataBuildingContext() def root = new RootClass(metadataBuildingContext) root.setEntityName("MyEntity") root.setTable(new Table("my_entity")) - - def embeddedProp = Mock(TestEmbedded) + def associatedEntity = GroovyMock(GrailsHibernatePersistentEntity) - - embeddedProp.getType() >> Address - embeddedProp.getName() >> "address" - embeddedProp.getAssociatedEntity() >> associatedEntity - embeddedProp.getOwner() >> Mock(GrailsHibernatePersistentEntity) { - getJavaClass() >> MyEntity - } - embeddedProp.isValidHibernateOneToOne() >> false - embeddedProp.isValidHibernateManyToOne() >> false + def embeddedProp = mockEmbeddedProperty(associatedEntity, "address", Address) + + // The Fix: Mock must return the root class so .getTable() doesn't NPE + associatedEntity.getPersistentClass() >> root - associatedEntity.getName() >> "Address" - def prop1 = Mock(TestSimple) + def prop1 = Mock(HibernateSimpleProperty) prop1.getName() >> "street" prop1.getType() >> String - prop1.isValidHibernateOneToOne() >> false - prop1.isValidHibernateManyToOne() >> false + associatedEntity.getHibernateParentProperty(MyEntity) >> Optional.empty() associatedEntity.getHibernatePersistentProperties(MyEntity) >> [prop1] - def mappings = metadataBuildingContext.getMetadataCollector() - when: def component = binder.bindComponent(root, embeddedProp, "") @@ -140,44 +74,28 @@ class ComponentBinderSpec extends HibernateGormDatastoreSpec { given: def metadataBuildingContext = getGrailsDomainBinder().getMetadataBuildingContext() def root = new RootClass(metadataBuildingContext) - root.setEntityName("MyEntity") root.setTable(new Table("my_entity")) - def embeddedProp = Mock(TestEmbedded) def associatedEntity = GroovyMock(GrailsHibernatePersistentEntity) + def embeddedProp = mockEmbeddedProperty(associatedEntity, "address", Address) - embeddedProp.getType() >> Address - embeddedProp.getName() >> "address" - embeddedProp.getAssociatedEntity() >> associatedEntity - embeddedProp.getOwner() >> Mock(GrailsHibernatePersistentEntity) { - getJavaClass() >> MyEntity - } - embeddedProp.isValidHibernateOneToOne() >> false - embeddedProp.isValidHibernateManyToOne() >> false + associatedEntity.getPersistentClass() >> root - associatedEntity.getName() >> "Address" def idProp = Mock(org.grails.orm.hibernate.cfg.domainbinding.hibernate.HibernateIdentityProperty) idProp.getName() >> "id" - def versionProp = Mock(TestSimple) - versionProp.getName() >> "version" - def normalProp = Mock(TestSimple) + + def normalProp = Mock(HibernateSimpleProperty) normalProp.getName() >> "street" normalProp.getType() >> String - normalProp.isValidHibernateOneToOne() >> false - normalProp.isValidHibernateManyToOne() >> false - associatedEntity.getIdentity() >> idProp associatedEntity.getHibernateParentProperty(MyEntity) >> Optional.empty() associatedEntity.getHibernatePersistentProperties(MyEntity) >> [normalProp] - def mappings = metadataBuildingContext.getMetadataCollector() - when: binder.bindComponent(root, embeddedProp, "") then: 0 * componentUpdater.updateComponent(_, _, idProp, _) - 0 * componentUpdater.updateComponent(_, _, versionProp, _) 1 * grailsPropertyBinder.bindProperty(root, root.getTable(), "address", embeddedProp, normalProp) >> new BasicValue(metadataBuildingContext, root.getTable()) 1 * componentUpdater.updateComponent(_, _, normalProp, _) } @@ -186,42 +104,38 @@ class ComponentBinderSpec extends HibernateGormDatastoreSpec { given: def metadataBuildingContext = getGrailsDomainBinder().getMetadataBuildingContext() def root = new RootClass(metadataBuildingContext) - root.setEntityName("MyEntity") root.setTable(new Table("my_entity")) - def embeddedProp = Mock(TestEmbedded) def associatedEntity = GroovyMock(GrailsHibernatePersistentEntity) + def embeddedProp = mockEmbeddedProperty(associatedEntity, "address", Address) - embeddedProp.getType() >> Address - embeddedProp.getName() >> "address" - embeddedProp.getAssociatedEntity() >> associatedEntity - embeddedProp.getOwner() >> Mock(GrailsHibernatePersistentEntity) { - getJavaClass() >> MyEntity - } - embeddedProp.isValidHibernateOneToOne() >> false - embeddedProp.isValidHibernateManyToOne() >> false + associatedEntity.getPersistentClass() >> root - associatedEntity.getName() >> "Address" - def parentProp = Mock(TestSimple) + def parentProp = Mock(HibernateSimpleProperty) parentProp.getName() >> "myEntity" - parentProp.getType() >> MyEntity - associatedEntity.getIdentity() >> null associatedEntity.getHibernateParentProperty(MyEntity) >> Optional.of(parentProp) associatedEntity.getHibernatePersistentProperties(MyEntity) >> [] - def mappings = metadataBuildingContext.getMetadataCollector() - when: def component = binder.bindComponent(root, embeddedProp, "") then: component.getParentProperty() == "myEntity" - 0 * grailsPropertyBinder.bindProperty(_, _, _, _, parentProp, _) - 0 * componentUpdater.updateComponent(_, _, parentProp, _) + } + + // Helper to reduce boilerplate + private HibernateEmbeddedProperty mockEmbeddedProperty(GrailsHibernatePersistentEntity associatedEntity, String name, Class type) { + def embeddedProp = Mock(HibernateEmbeddedProperty) + embeddedProp.getName() >> name + embeddedProp.getType() >> type + embeddedProp.getAssociatedEntity() >> associatedEntity + embeddedProp.getOwner() >> Mock(GrailsHibernatePersistentEntity) { + getJavaClass() >> MyEntity + } + return embeddedProp } static class MyEntity {} static class Address {} - enum MyEnum { VAL } -} +} \ No newline at end of file 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 a12a5ee5e2..d499865567 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 @@ -3,23 +3,18 @@ package org.grails.orm.hibernate.cfg.domainbinding import grails.gorm.specs.HibernateGormDatastoreSpec import org.grails.orm.hibernate.cfg.domainbinding.hibernate.HibernatePersistentProperty import org.grails.orm.hibernate.cfg.CompositeIdentity -import org.grails.orm.hibernate.cfg.domainbinding.hibernate.GrailsHibernatePersistentEntity - import org.grails.orm.hibernate.cfg.domainbinding.hibernate.HibernatePersistentEntity import org.hibernate.mapping.Component import org.hibernate.mapping.RootClass import org.hibernate.mapping.Table +import org.hibernate.mapping.Value import spock.lang.Subject - -import org.grails.orm.hibernate.cfg.domainbinding.binder.ComponentBinder import org.grails.orm.hibernate.cfg.domainbinding.binder.CompositeIdBinder import org.grails.orm.hibernate.cfg.domainbinding.binder.ComponentUpdater import org.grails.orm.hibernate.cfg.domainbinding.binder.GrailsPropertyBinder -import org.hibernate.mapping.Value class CompositeIdBinderSpec extends HibernateGormDatastoreSpec { - def componentBinder = Mock(ComponentBinder) def componentUpdater = Mock(ComponentUpdater) def grailsPropertyBinder = Mock(GrailsPropertyBinder) @@ -27,7 +22,11 @@ class CompositeIdBinderSpec extends HibernateGormDatastoreSpec { CompositeIdBinder binder def setup() { - binder = new CompositeIdBinder(getGrailsDomainBinder().getMetadataBuildingContext(), componentUpdater, grailsPropertyBinder) + binder = new CompositeIdBinder( + getGrailsDomainBinder().getMetadataBuildingContext(), + componentUpdater, + grailsPropertyBinder + ) } def "should bind composite id using property names from CompositeIdentity"() { @@ -36,20 +35,20 @@ class CompositeIdBinderSpec extends HibernateGormDatastoreSpec { def metadataBuildingContext = getGrailsDomainBinder().getMetadataBuildingContext() def root = new RootClass(metadataBuildingContext) root.setEntityName("MyEntity") - def mappings = metadataBuildingContext.getMetadataCollector() - - def compositeIdentity = new CompositeIdentity(propertyNames: ['prop1', 'prop2'] as String[]) - + def table = new Table("my_entity") + root.setTable(table) + + // FIX: Stub the persistent class return + domainClass.getPersistentClass() >> root + + def compositeIdentity = Mock(CompositeIdentity) def prop1 = Mock(HibernatePersistentProperty) def prop2 = Mock(HibernatePersistentProperty) def identifierProp = Mock(HibernatePersistentProperty) - domainClass.getHibernatePropertyByName("prop1") >> prop1 - domainClass.getHibernatePropertyByName("prop2") >> prop2 + + compositeIdentity.getHibernateProperties(domainClass) >> ([prop1, prop2] as HibernatePersistentProperty[]) domainClass.getIdentity() >> identifierProp domainClass.getName() >> "MyEntity" - - def table = new Table("my_entity") - root.setTable(table) when: binder.bindCompositeId(domainClass, root, compositeIdentity) @@ -68,16 +67,17 @@ class CompositeIdBinderSpec extends HibernateGormDatastoreSpec { def metadataBuildingContext = getGrailsDomainBinder().getMetadataBuildingContext() def root = new RootClass(metadataBuildingContext) root.setEntityName("MyEntity") - def mappings = metadataBuildingContext.getMetadataCollector() - + def table = new Table("my_entity") + root.setTable(table) + + // FIX: Stub the persistent class return + domainClass.getPersistentClass() >> root + def prop1 = Mock(HibernatePersistentProperty) def identifierProp = Mock(HibernatePersistentProperty) domainClass.getCompositeIdentity() >> ([prop1] as HibernatePersistentProperty[]) domainClass.getIdentity() >> identifierProp domainClass.getName() >> "MyEntity" - - def table = new Table("my_entity") - root.setTable(table) when: binder.bindCompositeId(domainClass, root, null) @@ -93,7 +93,7 @@ class CompositeIdBinderSpec extends HibernateGormDatastoreSpec { def metadataBuildingContext = getGrailsDomainBinder().getMetadataBuildingContext() def root = new RootClass(metadataBuildingContext) root.setEntityName("MyEntity") - def mappings = metadataBuildingContext.getMetadataCollector() + domainClass.getCompositeIdentity() >> null domainClass.getName() >> "MyEntity" @@ -103,4 +103,4 @@ class CompositeIdBinderSpec extends HibernateGormDatastoreSpec { then: thrown(org.hibernate.MappingException) } -} +} \ No newline at end of file
