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