You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@grails.apache.org by bo...@apache.org on 2026/04/06 19:16:59 UTC
(grails-core) 09/12: H7: encapsulate collection configuration within HibernateToManyProperty
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 00e5bb8fedbbed3936c3c66da3656e9ca952442d
Author: Walter Duque de Estrada <wb...@mac.com>
AuthorDate: Sun Apr 5 19:36:27 2026 -0500
H7: encapsulate collection configuration within HibernateToManyProperty
---
.../cfg/domainbinding/binder/CollectionBinder.java | 18 +--------
.../hibernate/HibernateBasicProperty.java | 4 +-
.../HibernateEmbeddedCollectionProperty.java | 4 +-
.../hibernate/HibernateManyToManyProperty.java | 4 +-
.../hibernate/HibernateOneToManyProperty.java | 4 +-
.../hibernate/HibernateToManyProperty.java | 28 +++++++++++++-
.../cfg/domainbinding/CollectionBinderSpec.groovy | 44 ++++++++++++++--------
.../TableForManyCalculatorSpec.groovy | 3 ++
.../HibernateManyToManyPropertySpec.groovy | 37 ++++++++++++++++++
9 files changed, 105 insertions(+), 41 deletions(-)
diff --git a/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/cfg/domainbinding/binder/CollectionBinder.java b/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/cfg/domainbinding/binder/CollectionBinder.java
index 04d91e5381..21f840708e 100644
--- a/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/cfg/domainbinding/binder/CollectionBinder.java
+++ b/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/cfg/domainbinding/binder/CollectionBinder.java
@@ -131,9 +131,8 @@ public class CollectionBinder {
* @return the result
*/
public Collection bindCollection(HibernateToManyProperty property, String path) {
- Collection collection = initializeCollection(property, path);
-
- configureCollectionMetadata(property, collection);
+ Collection collection = collectionHolder.create(property);
+ property.setCollection(collection, path);
if (property.shouldBindWithForeignKey()) {
bindOneToManyElement((HibernateToManyEntityProperty) property, collection);
@@ -148,19 +147,6 @@ public class CollectionBinder {
return collection;
}
- private Collection initializeCollection(HibernateToManyProperty property, String path) {
- Collection collection = collectionHolder.create(property);
- property.setCollection(collection);
- collection.setRole(property.getRole(path));
- return collection;
- }
-
- private void configureCollectionMetadata(HibernateToManyProperty property, Collection collection) {
- collection.setFetchMode(property.getFetchMode());
- collection.setOrphanDelete(ALL_DELETE_ORPHAN.getValue().equals(property.getCascade()));
- collection.setBatchSize(property.getBatchSize());
- }
-
private void bindOneToManyElement(HibernateToManyEntityProperty property, Collection collection) {
OneToMany oneToMany = new OneToMany(metadataBuildingContext, collection.getOwner());
oneToMany.setReferencedEntityName(property.getHibernateAssociatedEntity().getName());
diff --git a/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/cfg/domainbinding/hibernate/HibernateBasicProperty.java b/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/cfg/domainbinding/hibernate/HibernateBasicProperty.java
index 565781defc..7aa1f98a41 100644
--- a/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/cfg/domainbinding/hibernate/HibernateBasicProperty.java
+++ b/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/cfg/domainbinding/hibernate/HibernateBasicProperty.java
@@ -37,12 +37,12 @@ public class HibernateBasicProperty extends BasicWithMapping<PropertyConfig> imp
}
@Override
- public Collection getCollection() {
+ public Collection getHibernateCollection() {
return collection;
}
@Override
- public void setCollection(Collection collection) {
+ public void setHibernateCollection(Collection collection) {
this.collection = collection;
}
}
diff --git a/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/cfg/domainbinding/hibernate/HibernateEmbeddedCollectionProperty.java b/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/cfg/domainbinding/hibernate/HibernateEmbeddedCollectionProperty.java
index 0769b42ba6..3ddc4e4b7b 100644
--- a/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/cfg/domainbinding/hibernate/HibernateEmbeddedCollectionProperty.java
+++ b/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/cfg/domainbinding/hibernate/HibernateEmbeddedCollectionProperty.java
@@ -41,12 +41,12 @@ public class HibernateEmbeddedCollectionProperty extends EmbeddedCollectionWithM
}
@Override
- public Collection getCollection() {
+ public Collection getHibernateCollection() {
return collection;
}
@Override
- public void setCollection(Collection collection) {
+ public void setHibernateCollection(Collection collection) {
this.collection = collection;
}
}
diff --git a/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/cfg/domainbinding/hibernate/HibernateManyToManyProperty.java b/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/cfg/domainbinding/hibernate/HibernateManyToManyProperty.java
index 488655ba96..6192c85bde 100644
--- a/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/cfg/domainbinding/hibernate/HibernateManyToManyProperty.java
+++ b/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/cfg/domainbinding/hibernate/HibernateManyToManyProperty.java
@@ -48,12 +48,12 @@ public class HibernateManyToManyProperty extends ManyToManyWithMapping<PropertyC
}
@Override
- public Collection getCollection() {
+ public Collection getHibernateCollection() {
return collection;
}
@Override
- public void setCollection(Collection collection) {
+ public void setHibernateCollection(Collection collection) {
this.collection = collection;
}
diff --git a/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/cfg/domainbinding/hibernate/HibernateOneToManyProperty.java b/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/cfg/domainbinding/hibernate/HibernateOneToManyProperty.java
index 02654871cb..88579c512b 100644
--- a/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/cfg/domainbinding/hibernate/HibernateOneToManyProperty.java
+++ b/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/cfg/domainbinding/hibernate/HibernateOneToManyProperty.java
@@ -50,12 +50,12 @@ public class HibernateOneToManyProperty extends OneToManyWithMapping<PropertyCon
}
@Override
- public Collection getCollection() {
+ public Collection getHibernateCollection() {
return collection;
}
@Override
- public void setCollection(Collection collection) {
+ public void setHibernateCollection(Collection collection) {
this.collection = collection;
}
diff --git a/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/cfg/domainbinding/hibernate/HibernateToManyProperty.java b/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/cfg/domainbinding/hibernate/HibernateToManyProperty.java
index a4628ca94c..15cc2e5af1 100644
--- a/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/cfg/domainbinding/hibernate/HibernateToManyProperty.java
+++ b/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/cfg/domainbinding/hibernate/HibernateToManyProperty.java
@@ -23,6 +23,7 @@ import java.util.Optional;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.hibernate.FetchMode;
+import org.hibernate.MappingException;
import org.hibernate.mapping.Collection;
import org.hibernate.mapping.IndexedCollection;
@@ -41,6 +42,7 @@ import org.grails.orm.hibernate.cfg.domainbinding.util.BackticksRemover;
import static java.util.Optional.ofNullable;
import static org.grails.orm.hibernate.cfg.GrailsHibernateUtil.qualify;
import static org.grails.orm.hibernate.cfg.domainbinding.binder.GrailsDomainBinder.UNDERSCORE;
+import static org.grails.orm.hibernate.cfg.domainbinding.util.CascadeBehavior.ALL_DELETE_ORPHAN;
/** Marker interface for Hibernate to-many associations */
public interface HibernateToManyProperty extends PropertyWithMapping<PropertyConfig>, HibernateAssociation {
@@ -246,9 +248,31 @@ public interface HibernateToManyProperty extends PropertyWithMapping<PropertyCon
return isNullable();
}
- Collection getCollection();
+ default Collection getCollection() {
+ Collection collection = getHibernateCollection();
+ if (collection == null) {
+ throw new MappingException("Hibernate Collection has not been initialized for property [" + getName() + "]. Call setCollection() first.");
+ }
+ return collection;
+ }
+
+ default void setCollection(Collection collection) {
+ setCollection(collection, "");
+ }
+
+ default void setCollection(Collection collection, String path) {
+ if (collection != null) {
+ collection.setRole(getRole(path));
+ collection.setFetchMode(getFetchMode());
+ collection.setOrphanDelete(ALL_DELETE_ORPHAN.getValue().equals(getCascade()));
+ collection.setBatchSize(getBatchSize());
+ }
+ setHibernateCollection(collection);
+ }
+
+ Collection getHibernateCollection();
- void setCollection(Collection collection);
+ void setHibernateCollection(Collection collection);
default String getCascade() {
return getHibernateMappedForm().getCascade();
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 9e6868f117..e7df64fe24 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
@@ -28,10 +28,13 @@ import org.grails.orm.hibernate.cfg.domainbinding.binder.EnumTypeBinder
import org.grails.orm.hibernate.cfg.domainbinding.binder.SimpleValueBinder
import org.grails.orm.hibernate.cfg.domainbinding.collectionType.CollectionHolder
import org.grails.orm.hibernate.cfg.domainbinding.hibernate.GrailsHibernatePersistentEntity
+import org.grails.orm.hibernate.cfg.domainbinding.hibernate.HibernateToManyProperty
+import org.grails.orm.hibernate.cfg.domainbinding.hibernate.HibernateToManyEntityProperty
import org.grails.orm.hibernate.cfg.domainbinding.util.ColumnNameForPropertyAndPathFetcher
import org.grails.orm.hibernate.cfg.domainbinding.util.DefaultColumnNameFetcher
import org.grails.orm.hibernate.cfg.domainbinding.util.SimpleValueColumnFetcher
import org.grails.orm.hibernate.cfg.domainbinding.util.BackticksRemover
+import org.grails.orm.hibernate.cfg.domainbinding.util.TableForManyCalculator
import org.hibernate.boot.spi.InFlightMetadataCollector
import org.hibernate.mapping.OneToMany
import org.hibernate.mapping.Table
@@ -40,6 +43,7 @@ class CollectionBinderSpec extends HibernateGormDatastoreSpec {
CollectionBinder binder
InFlightMetadataCollector mockCollector
+ TableForManyCalculator mockCalculator
void setup() {
def gdb = getGrailsDomainBinder()
@@ -51,7 +55,11 @@ class CollectionBinderSpec extends HibernateGormDatastoreSpec {
getBootstrapContext() >> mbc.getMetadataCollector().getBootstrapContext()
getDatabase() >> mbc.getMetadataCollector().getDatabase()
addTable(_, _, _, _, _, _) >> { schema, catalog, name, sub, isAbstract, context ->
- return new Table("test", name)
+ return new Table("test", name).with {
+ setSchema(schema)
+ setCatalog(catalog)
+ return it
+ }
}
}
@@ -64,44 +72,50 @@ class CollectionBinderSpec extends HibernateGormDatastoreSpec {
def citmto = new CompositeIdentifierToManyToOneBinder(new org.grails.orm.hibernate.cfg.domainbinding.util.ForeignKeyColumnCountCalculator(), ns, dcnf, backticksRemover, svb)
def mtob = new ManyToOneBinder(mbc, ns, svb, new ManyToOneValuesBinder(), citmto)
def ch = new CollectionHolder(mbc)
- def tfmc = new org.grails.orm.hibernate.cfg.domainbinding.util.TableForManyCalculator(ns, mockCollector)
+ mockCalculator = Mock(TableForManyCalculator)
- binder = new CollectionBinder(mbc, ns, svb, etb, mtob, citmto, svcf, ch, mockCollector, tfmc)
+ binder = new CollectionBinder(mbc, ns, svb, etb, mtob, citmto, svcf, ch, mockCollector, mockCalculator)
}
def setupSpec() {
manager.addAllDomainClasses([Person, Pet, CBManyToManyA, CBManyToManyB])
}
- void "test bindCollection for one-to-many"() {
+ void "test bindCollection delegates configuration to property.setCollection"() {
given:
def personEntity = mappingContext.getPersistentEntity(Person.name) as GrailsHibernatePersistentEntity
- def petsProp = personEntity.getPropertyByName("pets")
+ def petsProp = personEntity.getPropertyByName("pets") as HibernateToManyEntityProperty
when:
- def collection = binder.bindCollection(petsProp, "")
+ def collection = binder.bindCollection(petsProp, "my.path")
then:
1 * mockCollector.addCollectionBinding(_)
- collection.role == "${Person.name}.pets".toString()
- collection.element instanceof OneToMany
- (collection.element as OneToMany).referencedEntityName == Pet.name
+ collection.role == "${Person.name}.my.path.pets".toString()
+ collection.fetchMode == petsProp.getFetchMode()
+ collection.batchSize == petsProp.getBatchSize()
+
+ and: "Property has been initialized"
+ petsProp.getCollection() == collection
}
- void "test bindCollection for many-to-many uses join table"() {
+ void "test bindCollection for many-to-many uses calculator"() {
given:
def entityA = mappingContext.getPersistentEntity(CBManyToManyA.name) as GrailsHibernatePersistentEntity
- def othersProp = entityA.getPropertyByName("others")
+ def othersProp = entityA.getPropertyByName("others") as HibernateToManyProperty
+
+ mockCalculator.getTableName(othersProp) >> "custom_join_table"
+ mockCalculator.getJoinTableSchema(othersProp) >> "custom_schema"
+ mockCalculator.getJoinTableCatalog(othersProp) >> "custom_catalog"
when:
def collection = binder.bindCollection(othersProp, "")
then:
1 * mockCollector.addCollectionBinding(_)
- collection.role == "${CBManyToManyA.name}.others".toString()
- !collection.isOneToMany()
- collection.collectionTable != null
- collection.collectionTable.name == "cbmany_to_manya_others"
+ collection.collectionTable.name == "custom_join_table"
+ collection.collectionTable.schema == "custom_schema"
+ collection.collectionTable.catalog == "custom_catalog"
}
}
diff --git a/grails-data-hibernate7/core/src/test/groovy/org/grails/orm/hibernate/cfg/domainbinding/TableForManyCalculatorSpec.groovy b/grails-data-hibernate7/core/src/test/groovy/org/grails/orm/hibernate/cfg/domainbinding/TableForManyCalculatorSpec.groovy
index d02cbc58bf..bc64ebdb5a 100644
--- a/grails-data-hibernate7/core/src/test/groovy/org/grails/orm/hibernate/cfg/domainbinding/TableForManyCalculatorSpec.groovy
+++ b/grails-data-hibernate7/core/src/test/groovy/org/grails/orm/hibernate/cfg/domainbinding/TableForManyCalculatorSpec.groovy
@@ -42,6 +42,9 @@ class TableForManyCalculatorSpec extends HibernateGormDatastoreSpec {
def namingStrategy = getGrailsDomainBinder().getNamingStrategy()
def backticksRemover = new BackticksRemover()
def collector = Mock(InFlightMetadataCollector)
+ collector.addTable(_, _, _, _, _, _) >> { schema, catalog, name, sub, isAbstract, context ->
+ return new org.hibernate.mapping.Table("test", name)
+ }
def calculator = new TableForManyCalculator(namingStrategy, collector, backticksRemover)
diff --git a/grails-data-hibernate7/core/src/test/groovy/org/grails/orm/hibernate/cfg/domainbinding/hibernate/HibernateManyToManyPropertySpec.groovy b/grails-data-hibernate7/core/src/test/groovy/org/grails/orm/hibernate/cfg/domainbinding/hibernate/HibernateManyToManyPropertySpec.groovy
index e62ab1ea88..4dd8f5437f 100644
--- a/grails-data-hibernate7/core/src/test/groovy/org/grails/orm/hibernate/cfg/domainbinding/hibernate/HibernateManyToManyPropertySpec.groovy
+++ b/grails-data-hibernate7/core/src/test/groovy/org/grails/orm/hibernate/cfg/domainbinding/hibernate/HibernateManyToManyPropertySpec.groovy
@@ -31,6 +31,11 @@ class HibernateManyToManyPropertySpec extends HibernateGormDatastoreSpec {
given:
def entityA = (HibernatePersistentEntity) getMappingContext().getPersistentEntity(HMMPA.name)
def property = (HibernateManyToManyProperty) entityA.getPropertyByName("others")
+ def mbc = getGrailsDomainBinder().metadataBuildingContext
+ def rootClass = new org.hibernate.mapping.RootClass(mbc)
+ rootClass.setEntityName(HMMPA.name)
+ def mockCollection = new org.hibernate.mapping.Set(mbc, rootClass)
+ property.setCollection(mockCollection, "")
expect:
property.getHibernateAssociatedEntity().name == HMMPB.name
@@ -40,6 +45,38 @@ class HibernateManyToManyPropertySpec extends HibernateGormDatastoreSpec {
property.isLazy()
!property.isAssociationColumnNullable()
}
+
+ def "test getCollection throws exception if not initialized"() {
+ given:
+ def entityA = (HibernatePersistentEntity) getMappingContext().getPersistentEntity(HMMPA.name)
+ def property = (HibernateManyToManyProperty) entityA.getPropertyByName("others")
+
+ when:
+ property.getCollection()
+
+ then:
+ def e = thrown(org.hibernate.MappingException)
+ e.message.contains("Hibernate Collection has not been initialized")
+ }
+
+ def "test setCollection with path configures metadata"() {
+ given:
+ def entityA = (HibernatePersistentEntity) getMappingContext().getPersistentEntity(HMMPA.name)
+ def property = (HibernateManyToManyProperty) entityA.getPropertyByName("others")
+ def mbc = getGrailsDomainBinder().metadataBuildingContext
+ def rootClass = new org.hibernate.mapping.RootClass(mbc)
+ rootClass.setEntityName(HMMPA.name)
+ def mockCollection = new org.hibernate.mapping.Set(mbc, rootClass)
+
+ when:
+ property.setCollection(mockCollection, "foo.bar")
+
+ then:
+ property.getCollection() == mockCollection
+ mockCollection.getRole() == "${HMMPA.name}.foo.bar.others".toString()
+ mockCollection.getFetchMode() == property.getFetchMode()
+ mockCollection.getBatchSize() == property.getBatchSize()
+ }
}
@Entity