This is an automated email from the ASF dual-hosted git repository.

borinquenkid pushed a commit to branch 8.0.x-hibernate7
in repository https://gitbox.apache.org/repos/asf/grails-core.git

commit 273b8136a998a3837d5c4e73a4d5949ba74d5b00
Author: Walter Duque de Estrada <[email protected]>
AuthorDate: Tue Feb 10 08:24:17 2026 -0600

    Changes made:
    
       1. `GrailsHibernatePersistentProperty.java`:
           * Rewrote isColumnNullable() using Optional chains for a more 
functional style:
    
       1         default boolean isColumnNullable() {
       2             return Optional.ofNullable(getHibernateOwner())
       3                     .filter(owner -> !owner.isRoot())
       4                     .map(owner -> 
Optional.ofNullable(owner.getMappedForm())
       5                             .map(Mapping::getTablePerHierarchy)
       6                             .orElse(false) || isNullable())
       7                     .orElse(false);
       8         }
    
       2. `GrailsHibernatePersistentPropertySpec.groovy`:
           * Expanded the test suite to cover all methods in the interface.
           * Added tests for isHibernateOneToOne, isHibernateManyToOne, 
isTablePerHierarchySubclass, isColumnNullable, getIndexColumnName, and 
getMapElementName.
           * Added a test case for validateAssociation to ensure it correctly 
throws a MappingException when an association is mapped to a user type.
           * Included necessary entity classes (BaseTPH, SubTPH, 
SubTablePerClass, etc.) to support testing different inheritance and mapping 
scenarios.
---
 .../cfg/GrailsHibernatePersistentProperty.java     |  10 ++
 .../hibernate/cfg/domainbinding/ColumnBinder.java  |   7 +-
 .../GrailsHibernatePersistentPropertySpec.groovy   | 104 +++++++++++++++++++++
 3 files changed, 116 insertions(+), 5 deletions(-)

diff --git 
a/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/cfg/GrailsHibernatePersistentProperty.java
 
b/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/cfg/GrailsHibernatePersistentProperty.java
index 4139f889d6..a983df2a81 100644
--- 
a/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/cfg/GrailsHibernatePersistentProperty.java
+++ 
b/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/cfg/GrailsHibernatePersistentProperty.java
@@ -4,6 +4,7 @@ import org.grails.datastore.mapping.model.PersistentProperty;
 import org.grails.datastore.mapping.model.types.Association;
 import org.grails.datastore.mapping.model.types.Embedded;
 
+import java.util.Objects;
 import java.util.Optional;
 
 import org.hibernate.MappingException;
@@ -135,5 +136,14 @@ public interface GrailsHibernatePersistentProperty extends 
PersistentProperty<Pr
                 .orElseGet(() -> namingStrategy.resolveColumnName(getName()) + 
GrailsDomainBinder.UNDERSCORE + IndexedCollection.DEFAULT_ELEMENT_COLUMN_NAME);
     }
 
+    default boolean isColumnNullable() {
+        return Optional.ofNullable(getHibernateOwner())
+                .filter(owner -> !owner.isRoot())
+                .map(owner -> Optional.ofNullable(owner.getMappedForm())
+                        .map(Mapping::getTablePerHierarchy)
+                        .orElse(false) || isNullable())
+                .orElse(false);
+    }
+
 
 }
\ No newline at end of file
diff --git 
a/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/cfg/domainbinding/ColumnBinder.java
 
b/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/cfg/domainbinding/ColumnBinder.java
index 3f06b1b823..188a9c6310 100644
--- 
a/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/cfg/domainbinding/ColumnBinder.java
+++ 
b/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/cfg/domainbinding/ColumnBinder.java
@@ -127,12 +127,9 @@ public class ColumnBinder {
         createKeyForProps.createKeyForProps(property, path, table, columnName);
         indexBinder.bindIndex(columnName, column, cc, table);
 
-        final PersistentEntity owner = property.getOwner();
+        var owner = property.getHibernateOwner();
         if (!owner.isRoot()) {
-            Mapping mapping = null;
-            if (owner instanceof GrailsHibernatePersistentEntity 
persistentEntity) {
-                mapping = persistentEntity.getMappedForm();
-            }
+            Mapping mapping = owner.getMappedForm();
             if (mapping != null && mapping.getTablePerHierarchy()) {
                 if (LOG.isDebugEnabled())
                     LOG.debug("[GrailsDomainBinder] Sub class property [" + 
property.getName() + "] for column name [" + column.getName() + "] set to 
nullable");
diff --git 
a/grails-data-hibernate7/core/src/test/groovy/org/grails/orm/hibernate/cfg/GrailsHibernatePersistentPropertySpec.groovy
 
b/grails-data-hibernate7/core/src/test/groovy/org/grails/orm/hibernate/cfg/GrailsHibernatePersistentPropertySpec.groovy
index c6dd181adf..fbdf9135eb 100644
--- 
a/grails-data-hibernate7/core/src/test/groovy/org/grails/orm/hibernate/cfg/GrailsHibernatePersistentPropertySpec.groovy
+++ 
b/grails-data-hibernate7/core/src/test/groovy/org/grails/orm/hibernate/cfg/GrailsHibernatePersistentPropertySpec.groovy
@@ -4,6 +4,7 @@ import grails.gorm.annotation.Entity
 import grails.gorm.specs.HibernateGormDatastoreSpec
 import org.grails.datastore.mapping.model.PersistentEntity
 import org.grails.datastore.mapping.model.PersistentProperty
+import org.grails.orm.hibernate.cfg.domainbinding.NamingStrategyWrapper
 import spock.lang.Unroll
 
 class GrailsHibernatePersistentPropertySpec extends HibernateGormDatastoreSpec 
{
@@ -93,6 +94,83 @@ class GrailsHibernatePersistentPropertySpec extends 
HibernateGormDatastoreSpec {
         customMapProp.getIndexColumnType("long") == "long"
         listProp.getIndexColumnType("integer") == "integer"
     }
+
+    void "test isHibernateOneToOne and isHibernateManyToOne"() {
+        given:
+        createPersistentEntity(AssociatedEntity)
+        createPersistentEntity(ManyToOneEntity)
+        PersistentEntity entity = 
createPersistentEntity(TestEntityWithAssociations)
+        GrailsHibernatePersistentProperty oneToOneProp = 
(GrailsHibernatePersistentProperty) entity.getPropertyByName("oneToOne")
+        GrailsHibernatePersistentProperty manyToOneProp = 
(GrailsHibernatePersistentProperty) entity.getPropertyByName("manyToOne")
+
+        expect:
+        oneToOneProp.isHibernateOneToOne()
+        !oneToOneProp.isHibernateManyToOne()
+        !manyToOneProp.isHibernateOneToOne()
+        manyToOneProp.isHibernateManyToOne()
+    }
+
+    void "test isTablePerHierarchySubclass"() {
+        given:
+        createPersistentEntity(BaseTPH)
+        PersistentEntity subTPH = createPersistentEntity(SubTPH)
+        createPersistentEntity(BaseTablePerClass)
+        PersistentEntity subTPC = createPersistentEntity(SubTablePerClass)
+
+        GrailsHibernatePersistentProperty subTPHProp = 
(GrailsHibernatePersistentProperty) subTPH.getPropertyByName("subProp")
+        GrailsHibernatePersistentProperty subTPCProp = 
(GrailsHibernatePersistentProperty) subTPC.getPropertyByName("subProp")
+
+        expect:
+        subTPHProp.isTablePerHierarchySubclass()
+        !subTPCProp.isTablePerHierarchySubclass()
+    }
+
+    void "test isColumnNullable"() {
+        given:
+        PersistentEntity baseTPH = createPersistentEntity(BaseTPH)
+        PersistentEntity subTPH = createPersistentEntity(SubTPH)
+        PersistentEntity subTPC = createPersistentEntity(SubTablePerClass)
+
+        GrailsHibernatePersistentProperty baseTPHProp = 
(GrailsHibernatePersistentProperty) baseTPH.getPropertyByName("id")
+        GrailsHibernatePersistentProperty subTPHProp = 
(GrailsHibernatePersistentProperty) subTPH.getPropertyByName("subProp")
+        GrailsHibernatePersistentProperty subTPCProp = 
(GrailsHibernatePersistentProperty) subTPC.getPropertyByName("subProp")
+
+        expect:
+        !baseTPHProp.isColumnNullable() // Root is false
+        subTPHProp.isColumnNullable()   // Subclass TPH is true
+        !subTPCProp.isColumnNullable()  // Subclass not TPH uses isNullable() 
which is false by default
+    }
+
+    void "test getIndexColumnName and getMapElementName"() {
+        given:
+        def jdbcEnvironment = 
Mock(org.hibernate.engine.jdbc.env.spi.JdbcEnvironment)
+        def namingStrategy = new NamingStrategyWrapper(new 
org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl(), 
jdbcEnvironment)
+        PersistentEntity entityWithList = 
createPersistentEntity(EntityWithList)
+        PersistentEntity entityWithMap = createPersistentEntity(EntityWithMap)
+
+        GrailsHibernatePersistentProperty listProp = 
(GrailsHibernatePersistentProperty) entityWithList.getPropertyByName("items")
+        GrailsHibernatePersistentProperty mapProp = 
(GrailsHibernatePersistentProperty) entityWithMap.getPropertyByName("tags")
+
+        expect:
+        listProp.getIndexColumnName(namingStrategy) == "items_idx"
+        mapProp.getMapElementName(namingStrategy) == "tags_elt"
+    }
+
+    void "test validateAssociation throws exception for user type"() {
+        given:
+        PersistentEntity entity = 
createPersistentEntity(TestEntityWithAssociations)
+        GrailsHibernatePersistentProperty prop = 
(GrailsHibernatePersistentProperty) entity.getPropertyByName("manyToOne")
+        
+        // Mocking getUserType to return a non-null value for an association
+        def proxyProp = Spy(prop)
+        proxyProp.getUserType() >> String.class
+
+        when:
+        proxyProp.validateAssociation()
+
+        then:
+        thrown(org.hibernate.MappingException)
+    }
 }
 
 
@@ -201,3 +279,29 @@ class EntityWithList {
     List<String> items
     static hasMany = [items: String]
 }
+
+@Entity
+class BaseTPH {
+    Long id
+    static mapping = {
+        tablePerHierarchy true
+    }
+}
+
+@Entity
+class SubTPH extends BaseTPH {
+    String subProp
+}
+
+@Entity
+class BaseTablePerClass {
+    Long id
+    static mapping = {
+        tablePerHierarchy false
+    }
+}
+
+@Entity
+class SubTablePerClass extends BaseTablePerClass {
+    String subProp
+}

Reply via email to