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 cc37cc3467b57fe41bdae5b1ca9394decc877941
Author: Walter Duque de Estrada <[email protected]>
AuthorDate: Wed Mar 4 18:29:34 2026 -0600

    cleanup(hibernate7): ColumnBinder using more GrailsHibernate types
---
 .../cfg/domainbinding/binder/ColumnBinder.java     | 23 +++---------
 .../hibernate/HibernateAssociation.java            |  8 +++++
 .../hibernate/HibernateManyToManyProperty.java     |  5 +++
 .../hibernate/HibernateOneToOneProperty.java       |  9 +++++
 .../HibernateOneToOnePropertySpec.groovy           | 42 +++++++++++++++++++++-
 .../hibernate/HibernateToManyPropertySpec.groovy   | 27 +++++++++++++-
 6 files changed, 94 insertions(+), 20 deletions(-)

diff --git 
a/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/cfg/domainbinding/binder/ColumnBinder.java
 
b/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/cfg/domainbinding/binder/ColumnBinder.java
index d08d1b92a4..f6c5c053de 100644
--- 
a/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/cfg/domainbinding/binder/ColumnBinder.java
+++ 
b/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/cfg/domainbinding/binder/ColumnBinder.java
@@ -18,14 +18,11 @@
  */
 package org.grails.orm.hibernate.cfg.domainbinding.binder;
 
-import org.grails.datastore.mapping.model.types.Association;
-import org.grails.datastore.mapping.model.types.ToOne;
 import org.grails.orm.hibernate.cfg.ColumnConfig;
 import org.grails.orm.hibernate.cfg.Mapping;
 import org.grails.orm.hibernate.cfg.PersistentEntityNamingStrategy;
 import org.grails.orm.hibernate.cfg.PropertyConfig;
-import 
org.grails.orm.hibernate.cfg.domainbinding.hibernate.HibernateManyToManyProperty;
-import 
org.grails.orm.hibernate.cfg.domainbinding.hibernate.HibernateOneToOneProperty;
+import 
org.grails.orm.hibernate.cfg.domainbinding.hibernate.HibernateAssociation;
 import 
org.grails.orm.hibernate.cfg.domainbinding.hibernate.HibernatePersistentProperty;
 import org.grails.orm.hibernate.cfg.domainbinding.util.BackticksRemover;
 import 
org.grails.orm.hibernate.cfg.domainbinding.util.ColumnNameForPropertyAndPathFetcher;
@@ -81,9 +78,9 @@ public class ColumnBinder {
    * Binds a Column instance to the Hibernate meta model
    *
    * @param property The Grails domain class property
-   * @param parentProperty
+   * @param parentProperty parent property
    * @param column The column to bind
-   * @param path
+   * @param path the path
    * @param table The table name
    */
   public void bindColumn(
@@ -104,22 +101,12 @@ public class ColumnBinder {
     Class<?> userType = property.getUserType();
     String columnName =
         
columnNameForPropertyAndPathFetcher.getColumnNameForPropertyAndPath(property, 
path, cc);
-    if ((property instanceof Association association) && userType == null) {
+    if ((property instanceof HibernateAssociation assoc) && userType == null) {
       // Only use conventional naming when the column has not been explicitly 
mapped.
       if (column.getName() == null) {
         column.setName(columnName);
       }
-      if (property instanceof HibernateManyToManyProperty) {
-        column.setNullable(false);
-      } else if (property instanceof HibernateOneToOneProperty
-          && association.isBidirectional()
-          && !association.isOwningSide()) {
-          column.setNullable(!association.getInverseSide().isHasOne());
-      } else if ((property instanceof ToOne) && association.isCircular()) {
-        column.setNullable(true);
-      } else {
-        column.setNullable(true);
-      }
+      column.setNullable(assoc.isAssociationColumnNullable());
     } else {
       column.setName(columnName);
       column.setNullable(
diff --git 
a/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/cfg/domainbinding/hibernate/HibernateAssociation.java
 
b/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/cfg/domainbinding/hibernate/HibernateAssociation.java
index 5d71d7aa6f..d5cb2885fc 100644
--- 
a/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/cfg/domainbinding/hibernate/HibernateAssociation.java
+++ 
b/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/cfg/domainbinding/hibernate/HibernateAssociation.java
@@ -51,6 +51,14 @@ public interface HibernateAssociation extends 
HibernatePersistentProperty {
 
   boolean isBidirectionalOneToManyMap();
 
+  /**
+   * Returns the nullable value for the FK column when this property is an 
association without a
+   * user type. The default is {@code true}; subtypes override for their 
specific semantics.
+   */
+  default boolean isAssociationColumnNullable() {
+    return true;
+  }
+
   // --- Hibernate-typed overrides, removing instanceof guards ---
 
   /** Returns the inverse side as a {@link HibernateAssociation}, eliminating 
cast at call sites. */
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 d5d57d6e54..86ef2e79c4 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
@@ -41,4 +41,9 @@ public class HibernateManyToManyProperty extends 
ManyToManyWithMapping<PropertyC
   public HibernateManyToManyProperty getHibernateInverseSide() {
     return (HibernateManyToManyProperty) getInverseSide();
   }
+
+  @Override
+  public boolean isAssociationColumnNullable() {
+    return false;
+  }
 }
diff --git 
a/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/cfg/domainbinding/hibernate/HibernateOneToOneProperty.java
 
b/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/cfg/domainbinding/hibernate/HibernateOneToOneProperty.java
index ac85c3407f..166f8795c9 100644
--- 
a/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/cfg/domainbinding/hibernate/HibernateOneToOneProperty.java
+++ 
b/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/cfg/domainbinding/hibernate/HibernateOneToOneProperty.java
@@ -110,4 +110,13 @@ public class HibernateOneToOneProperty extends 
OneToOneWithMapping<PropertyConfi
     validateAssociation();
     return !isValidHibernateOneToOne();
   }
+
+  @Override
+  public boolean isAssociationColumnNullable() {
+    if (isBidirectional() && !isOwningSide()) {
+      HibernateOneToOneProperty inverseSide = getHibernateInverseSide();
+      return inverseSide == null || !inverseSide.isHasOne();
+    }
+    return true;
+  }
 }
diff --git 
a/grails-data-hibernate7/core/src/test/groovy/org/grails/orm/hibernate/cfg/domainbinding/HibernateOneToOnePropertySpec.groovy
 
b/grails-data-hibernate7/core/src/test/groovy/org/grails/orm/hibernate/cfg/domainbinding/HibernateOneToOnePropertySpec.groovy
index d178cfa3d8..a9e1855566 100644
--- 
a/grails-data-hibernate7/core/src/test/groovy/org/grails/orm/hibernate/cfg/domainbinding/HibernateOneToOnePropertySpec.groovy
+++ 
b/grails-data-hibernate7/core/src/test/groovy/org/grails/orm/hibernate/cfg/domainbinding/HibernateOneToOnePropertySpec.groovy
@@ -28,7 +28,7 @@ import org.hibernate.type.ForeignKeyDirection
 class HibernateOneToOnePropertySpec extends HibernateGormDatastoreSpec {
 
     def setupSpec() {
-        manager.addAllDomainClasses([OneToOneFace, OneToOneNose])
+        manager.addAllDomainClasses([OneToOneFace, OneToOneNose, OneToOneLeft, 
OneToOneRight])
     }
 
     void "getHibernateInverseSide returns HibernateOneToOneProperty"() {
@@ -132,6 +132,33 @@ class HibernateOneToOnePropertySpec extends 
HibernateGormDatastoreSpec {
         then:
         faceProp.needsSimpleValueBinding()
     }
+
+    void "isAssociationColumnNullable is false when bidirectional non-owning 
and inverse has hasOne"() {
+        when:
+        def noseEntity = mappingContext.getPersistentEntity(OneToOneNose.name)
+        def faceProp = noseEntity.persistentProperties.find { it.name == 
'face' } as HibernateOneToOneProperty
+
+        then:
+        !faceProp.isAssociationColumnNullable()
+    }
+
+    void "isAssociationColumnNullable is true when owning side declares 
hasOne"() {
+        when:
+        def faceEntity = mappingContext.getPersistentEntity(OneToOneFace.name)
+        def noseProp = faceEntity.persistentProperties.find { it.name == 
'nose' } as HibernateOneToOneProperty
+
+        then:
+        noseProp.isAssociationColumnNullable()
+    }
+
+    void "isAssociationColumnNullable is true when bidirectional non-owning 
but inverse does not have hasOne"() {
+        when:
+        def leftEntity = mappingContext.getPersistentEntity(OneToOneLeft.name)
+        def rightProp = leftEntity.persistentProperties.find { it.name == 
'right' } as HibernateOneToOneProperty
+
+        then:
+        rightProp.isAssociationColumnNullable()
+    }
 }
 
 @Entity
@@ -147,3 +174,16 @@ class OneToOneNose implements 
HibernateEntity<OneToOneNose> {
     OneToOneFace face
     static belongsTo = [face: OneToOneFace]
 }
+
+@Entity
+class OneToOneRight implements HibernateEntity<OneToOneRight> {
+    String code
+    OneToOneLeft left
+}
+
+@Entity
+class OneToOneLeft implements HibernateEntity<OneToOneLeft> {
+    String label
+    OneToOneRight right
+    static belongsTo = [right: OneToOneRight]
+}
diff --git 
a/grails-data-hibernate7/core/src/test/groovy/org/grails/orm/hibernate/cfg/domainbinding/hibernate/HibernateToManyPropertySpec.groovy
 
b/grails-data-hibernate7/core/src/test/groovy/org/grails/orm/hibernate/cfg/domainbinding/hibernate/HibernateToManyPropertySpec.groovy
index d597720af5..aaca72d0d3 100644
--- 
a/grails-data-hibernate7/core/src/test/groovy/org/grails/orm/hibernate/cfg/domainbinding/hibernate/HibernateToManyPropertySpec.groovy
+++ 
b/grails-data-hibernate7/core/src/test/groovy/org/grails/orm/hibernate/cfg/domainbinding/hibernate/HibernateToManyPropertySpec.groovy
@@ -25,7 +25,7 @@ import 
org.grails.orm.hibernate.cfg.domainbinding.hibernate.HibernateToManyPrope
 class HibernateToManyPropertySpec extends HibernateGormDatastoreSpec {
 
     def setupSpec() {
-        manager.addAllDomainClasses([HTMPBook, HTMPAuthor, HTMPAuthorCustom])
+        manager.addAllDomainClasses([HTMPBook, HTMPAuthor, HTMPAuthorCustom, 
HTMPStudent, HTMPCourse])
     }
 
     void "resolveJoinTableForeignKeyColumnName derives name from associated 
entity when no explicit config"() {
@@ -53,6 +53,15 @@ class HibernateToManyPropertySpec extends 
HibernateGormDatastoreSpec {
         then:
         columnName == "custom_book_fk"
     }
+
+    void "isAssociationColumnNullable returns false for ManyToMany"() {
+        when:
+        def studentEntity = 
mappingContext.getPersistentEntity(HTMPStudent.name)
+        def coursesProp = studentEntity.getPropertyByName("courses")
+
+        then:
+        !coursesProp.isAssociationColumnNullable()
+    }
 }
 
 @Entity
@@ -79,3 +88,19 @@ class HTMPAuthorCustom {
         books joinTable: [column: 'custom_book_fk']
     }
 }
+
+@Entity
+class HTMPStudent {
+    Long id
+    String name
+    Set<HTMPCourse> courses
+    static hasMany = [courses: HTMPCourse]
+}
+
+@Entity
+class HTMPCourse {
+    Long id
+    String title
+    Set<HTMPStudent> students
+    static hasMany = [students: HTMPStudent]
+}

Reply via email to