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


The following commit(s) were added to refs/heads/8.0.x-hibernate7-dev by this 
push:
     new ca40708e27 hibernate 7: update BindCollectionElementBinderSpec
ca40708e27 is described below

commit ca40708e2763d4d3fb0c09ab37e360234f9d9051
Author: Walter Duque de Estrada <[email protected]>
AuthorDate: Tue Mar 17 20:14:26 2026 -0500

    hibernate 7: update BindCollectionElementBinderSpec
---
 .../secondpass/BasicCollectionElementBinder.java   |  12 +-
 .../BasicCollectionElementBinderSpec.groovy        | 163 +++++++++++++++++++++
 2 files changed, 169 insertions(+), 6 deletions(-)

diff --git 
a/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/cfg/domainbinding/secondpass/BasicCollectionElementBinder.java
 
b/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/cfg/domainbinding/secondpass/BasicCollectionElementBinder.java
index e152f2b8e2..c27777524f 100644
--- 
a/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/cfg/domainbinding/secondpass/BasicCollectionElementBinder.java
+++ 
b/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/cfg/domainbinding/secondpass/BasicCollectionElementBinder.java
@@ -65,28 +65,28 @@ public class BasicCollectionElementBinder {
 
     /** Creates and binds a {@link BasicValue} element for the given basic 
collection property. */
     public BasicValue bind(HibernateToManyProperty property) {
-        Collection collection = property.getCollection();
         final Class<?> referencedType = property.getComponentType();
-        final boolean isEnum = referencedType.isEnum();
         var joinColumnMappingOptional =
                 
Optional.ofNullable(property.getMappedForm()).map(PropertyConfig::getJoinTableColumnConfig);
+        boolean present = joinColumnMappingOptional.isPresent();
         String columnName;
-        if (joinColumnMappingOptional.isPresent()) {
+        if (present) {
             columnName = joinColumnMappingOptional.get().getName();
         } else {
             var clazz = 
namingStrategy.resolveColumnName(referencedType.getName());
             var prop = namingStrategy.resolveTableName(property.getName());
-            columnName = isEnum
+            columnName = referencedType.isEnum()
                     ? clazz
                     : new BackticksRemover().apply(prop) + UNDERSCORE + new 
BackticksRemover().apply(clazz);
         }
-        if (isEnum) {
+        if (referencedType.isEnum()) {
             return enumTypeBinder.bindEnumTypeForColumn(property, columnName);
         } else {
             String typeName = property.getTypeName(referencedType);
+            Collection collection = property.getCollection();
             BasicValue element = simpleValueColumnBinder.bindSimpleValue(
                     metadataBuildingContext, collection.getCollectionTable(), 
typeName, columnName, true);
-            if (joinColumnMappingOptional.isPresent()) {
+            if (present) {
                 Column column = 
simpleValueColumnFetcher.getColumnForSimpleValue(element);
                 ColumnConfig columnConfig = joinColumnMappingOptional.get();
                 final PropertyConfig mappedForm = property.getMappedForm();
diff --git 
a/grails-data-hibernate7/core/src/test/groovy/org/grails/orm/hibernate/cfg/domainbinding/secondpass/BasicCollectionElementBinderSpec.groovy
 
b/grails-data-hibernate7/core/src/test/groovy/org/grails/orm/hibernate/cfg/domainbinding/secondpass/BasicCollectionElementBinderSpec.groovy
index 2cace08b8c..6747c23e98 100644
--- 
a/grails-data-hibernate7/core/src/test/groovy/org/grails/orm/hibernate/cfg/domainbinding/secondpass/BasicCollectionElementBinderSpec.groovy
+++ 
b/grails-data-hibernate7/core/src/test/groovy/org/grails/orm/hibernate/cfg/domainbinding/secondpass/BasicCollectionElementBinderSpec.groovy
@@ -80,6 +80,110 @@ class BasicCollectionElementBinderSpec extends 
HibernateGormDatastoreSpec {
         // Corrected: Match the 3-argument signature (Property, Class, String)
         1 * enumTypeBinder.bindEnumTypeForColumn(property, _ as String) >> 
mockValue
     }
+
+    void "test bind with custom column mapping and backticks"() {
+        given: "An entity with backticks in the mapping"
+        def entity = createPersistentEntity(BCEBCustom)
+        HibernateToManyProperty property = (HibernateToManyProperty) 
entity.getPropertyByName("flags")
+        property.setCollection(collectionWithTable("bceb_custom_flags"))
+
+        when: "The binder processes the property"
+        BasicValue element = binder.bind(property)
+
+        then: "The name is retrieved from mapping and backticks are handled by 
the mapping layer"
+        // Actual behavior: the mapping layer provides the name without 
backticks to the binder
+        element.getColumns().get(0).getName() == "flag_identifier"
+    }
+
+    void "test bind handles reserved words and removes backticks for default 
names"() {
+        given: "An entity using a reserved word property"
+        def entity = createPersistentEntity(BCEBReserved)
+        HibernateToManyProperty property = (HibernateToManyProperty) 
entity.getPropertyByName("group")
+        property.setCollection(collectionWithTable("bceb_reserved_group"))
+
+        when: "The binder processes the property"
+        BasicValue element = binder.bind(property)
+
+        then: "BackticksRemover ensures the concatenated name is clean"
+        // Targets Line 81: new BackticksRemover().apply(prop) + UNDERSCORE + 
...
+        element.getColumns().get(0).getName() == "group_java_lang_string"
+    }
+
+    void "test bindSimpleValue with default generated column name"() {
+        given: "A standard entity with no explicit mapping"
+        def entity = createPersistentEntity(BCEBDefault)
+        HibernateToManyProperty property = (HibernateToManyProperty) 
entity.getPropertyByName("tags")
+        property.setCollection(collectionWithTable("bceb_default_tags"))
+
+        when: "The binder processes the property"
+        BasicValue element = binder.bind(property)
+
+        then: "The column name is generated using the property and type name"
+        // Targets Line 81 for name generation and Line 87 for binding
+        element.getColumns().get(0).getName() == "tags_java_lang_string"
+    }
+
+    void "test bindSimpleValue with explicit mapped column name"() {
+        given: "An entity with an explicit join table column name"
+        def entity = createPersistentEntity(BCEBExplicit)
+        HibernateToManyProperty property = (HibernateToManyProperty) 
entity.getPropertyByName("flags")
+        property.setCollection(collectionWithTable("bceb_explicit_flags"))
+
+        when: "The binder processes the property"
+        BasicValue element = binder.bind(property)
+
+        then: "The column name is taken from the mapping configuration"
+        // Targets Line 75 for name retrieval and Line 87 for binding
+        element.getColumns().get(0).getName() == "custom_flag_col"
+
+        and: "The ColumnConfig is bound to the resulting column"
+        // Confirms the if (joinColumnMappingOptional.isPresent()) block at 
Line 89
+        element.getColumns().get(0).getValue() == element
+    }
+
+    void "Path 1: bindSimpleValue uses explicit mapping name"() {
+        given:
+        def entity = createPersistentEntity(BCEBPath1)
+        HibernateToManyProperty property = (HibernateToManyProperty) 
entity.getPropertyByName("flags")
+        property.setCollection(collectionWithTable("bceb_path1_table"))
+
+        when:
+        BasicValue element = binder.bind(property)
+
+        then: "columnName is taken directly from mapping (Line 75)"
+        element.getColumns().get(0).getName() == "explicit_col"
+    }
+
+    void "Path 2: bind delegates to enumTypeBinder for enum path"() {
+        given:
+        def entity = createPersistentEntity(BCEBPath2)
+        HibernateToManyProperty property = (HibernateToManyProperty) 
entity.getPropertyByName("statuses")
+        property.setCollection(collectionWithTable("bceb_path2_table"))
+        def mockValue = new 
BasicValue(getGrailsDomainBinder().metadataBuildingContext, 
property.getCollection().getCollectionTable())
+
+        when:
+        BasicValue element = binder.bind(property)
+
+        then: "columnName is the resolved fully qualified Enum class name"
+        // The namingStrategy resolves 
'org.grails.orm.hibernate.cfg.domainbinding.secondpass.BCEBStatus'
+        // to 
'org_grails_orm_hibernate_cfg_domainbinding_secondpass_bcebstatus'
+        1 * enumTypeBinder.bindEnumTypeForColumn(property, 
'org_grails_orm_hibernate_cfg_domainbinding_secondpass_bcebstatus') >> mockValue
+        element == mockValue
+    }
+
+    void "Path 3: bindSimpleValue uses concatenated property and type for 
scalars"() {
+        given:
+        def entity = createPersistentEntity(BCEBPath3)
+        HibernateToManyProperty property = (HibernateToManyProperty) 
entity.getPropertyByName("tags")
+        property.setCollection(collectionWithTable("bceb_path3_table"))
+
+        when:
+        BasicValue element = binder.bind(property)
+
+        then: "columnName is property + _ + type with backticks removed (Line 
81)"
+        // tags + _ + java_lang_string
+        element.getColumns().get(0).getName() == "tags_java_lang_string"
+    }
 }
 
 enum BCEBStatus { ACTIVE, INACTIVE }
@@ -90,4 +194,63 @@ class BCEBAuthor {
     java.util.Set<String> tags
     java.util.Set<BCEBStatus> statuses
     static hasMany = [tags: String, statuses: BCEBStatus]
+}
+
+@Entity
+class BCEBCustom {
+    Long id
+    java.util.Set<String> flags
+    static hasMany = [flags: String]
+    static mapping = {
+        // Targets the joinColumnMappingOptional branch (Line 74)
+        flags joinTable: [column: '`flag_identifier`']
+    }
+}
+
+@Entity
+class BCEBReserved {
+    Long id
+    java.util.Set<String> group // 'group' is a SQL reserved word
+    static hasMany = [group: String]
+}
+
+@Entity
+class BCEBDefault {
+    Long id
+    java.util.Set<String> tags
+    static hasMany = [tags: String]
+}
+
+@Entity
+class BCEBExplicit {
+    Long id
+    java.util.Set<String> flags
+    static hasMany = [flags: String]
+    static mapping = {
+        flags joinTable: [column: "custom_flag_col"]
+    }
+}
+
+@Entity
+class BCEBPath1 { // Explicit Mapping
+    Long id
+    java.util.Set<String> flags
+    static hasMany = [flags: String]
+    static mapping = {
+        flags joinTable: [column: "explicit_col"]
+    }
+}
+
+@Entity
+class BCEBPath2 { // Default Enum
+    Long id
+    java.util.Set<BCEBStatus> statuses
+    static hasMany = [statuses: BCEBStatus]
+}
+
+@Entity
+class BCEBPath3 { // Default Scalar
+    Long id
+    java.util.Set<String> tags
+    static hasMany = [tags: String]
 }
\ No newline at end of file

Reply via email to