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/02/13 04:11:17 UTC
(grails-core) 05/21: Changes made:
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 <wb...@mac.com>
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
+}