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 3f99835b138b0c89807de36f3e8e9a706415e7fb
Author: Walter Duque de Estrada <[email protected]>
AuthorDate: Tue Mar 17 16:10:00 2026 -0500

    hibernate 7: refactor ComponentBinder
---
 .../cfg/domainbinding/binder/ComponentBinder.java  |  4 +-
 .../domainbinding/binder/GrailsPropertyBinder.java |  2 +-
 .../cfg/domainbinding/ComponentBinderSpec.groovy   | 59 ++++++++++------------
 3 files changed, 30 insertions(+), 35 deletions(-)

diff --git 
a/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/cfg/domainbinding/binder/ComponentBinder.java
 
b/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/cfg/domainbinding/binder/ComponentBinder.java
index a00e4f4633..2f30d6b40d 100644
--- 
a/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/cfg/domainbinding/binder/ComponentBinder.java
+++ 
b/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/cfg/domainbinding/binder/ComponentBinder.java
@@ -52,8 +52,8 @@ public class ComponentBinder {
         this.grailsPropertyBinder = grailsPropertyBinder;
     }
 
-    public Component bindComponent(
-            PersistentClass owner, @Nonnull HibernateEmbeddedProperty 
embeddedProperty, String path) {
+    public Component bindComponent(@Nonnull HibernateEmbeddedProperty 
embeddedProperty, String path) {
+        var owner = embeddedProperty.getPersistentClass();
         Component component = new Component(metadataBuildingContext, owner);
         Class<?> type = embeddedProperty.getType();
         String role = GrailsHibernateUtil.qualify(type.getName(), 
embeddedProperty.getName());
diff --git 
a/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/cfg/domainbinding/binder/GrailsPropertyBinder.java
 
b/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/cfg/domainbinding/binder/GrailsPropertyBinder.java
index a409764173..faa0c85feb 100644
--- 
a/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/cfg/domainbinding/binder/GrailsPropertyBinder.java
+++ 
b/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/cfg/domainbinding/binder/GrailsPropertyBinder.java
@@ -87,7 +87,7 @@ public class GrailsPropertyBinder {
                 && !currentGrailsProp.isSerializableType()) {
             value = collectionBinder.bindCollection(toMany, path);
         } else if (currentGrailsProp instanceof HibernateEmbeddedProperty 
embedded) {
-            value = componentBinder.bindComponent(persistentClass, embedded, 
path);
+            value = componentBinder.bindComponent(embedded, path);
         } else {
             // HibernateSimpleProperty
             value = simpleValueBinder.bindSimpleValue(currentGrailsProp, 
parentProperty, table, path);
diff --git 
a/grails-data-hibernate7/core/src/test/groovy/org/grails/orm/hibernate/cfg/domainbinding/ComponentBinderSpec.groovy
 
b/grails-data-hibernate7/core/src/test/groovy/org/grails/orm/hibernate/cfg/domainbinding/ComponentBinderSpec.groovy
index 7d0127f761..a51f738920 100644
--- 
a/grails-data-hibernate7/core/src/test/groovy/org/grails/orm/hibernate/cfg/domainbinding/ComponentBinderSpec.groovy
+++ 
b/grails-data-hibernate7/core/src/test/groovy/org/grails/orm/hibernate/cfg/domainbinding/ComponentBinderSpec.groovy
@@ -1,33 +1,17 @@
-/*
- *  Licensed to the Apache Software Foundation (ASF) under one
- *  or more contributor license agreements.  See the NOTICE file
- *  distributed with this work for additional information
- *  regarding copyright ownership.  The ASF licenses this file
- *  to you under the Apache License, Version 2.0 (the
- *  "License"); you may not use this file except in compliance
- *  with the License.  You may obtain a copy of the License at
- *
- *    https://www.apache.org/licenses/LICENSE-2.0
- *
- *  Unless required by applicable law or agreed to in writing,
- *  software distributed under the License is distributed on an
- *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- *  KIND, either express or implied.  See the License for the
- *  specific language governing permissions and limitations
- *  under the License.
- */
-
 package org.grails.orm.hibernate.cfg.domainbinding
 
 import grails.gorm.specs.HibernateGormDatastoreSpec
+import org.grails.orm.hibernate.cfg.domainbinding.binder.GrailsPropertyBinder
 import 
org.grails.orm.hibernate.cfg.domainbinding.hibernate.GrailsHibernatePersistentEntity
 import org.grails.orm.hibernate.cfg.MappingCacheHolder
 import 
org.grails.orm.hibernate.cfg.domainbinding.hibernate.HibernateEmbeddedProperty
 import 
org.grails.orm.hibernate.cfg.domainbinding.hibernate.HibernateSimpleProperty
+import 
org.grails.orm.hibernate.cfg.domainbinding.hibernate.HibernateIdentityProperty
 import org.grails.orm.hibernate.cfg.domainbinding.binder.ComponentBinder
 import org.grails.orm.hibernate.cfg.domainbinding.binder.ComponentUpdater
 import org.hibernate.mapping.BasicValue
 import org.hibernate.mapping.Component
+import org.hibernate.mapping.PersistentClass
 import org.hibernate.mapping.RootClass
 import org.hibernate.mapping.Table
 import org.hibernate.mapping.Value
@@ -38,7 +22,7 @@ class ComponentBinderSpec extends HibernateGormDatastoreSpec {
     // Mock Collaborators
     MappingCacheHolder mappingCacheHolder = Mock(MappingCacheHolder)
     ComponentUpdater componentUpdater = Mock(ComponentUpdater)
-    org.grails.orm.hibernate.cfg.domainbinding.binder.GrailsPropertyBinder 
grailsPropertyBinder = 
Mock(org.grails.orm.hibernate.cfg.domainbinding.binder.GrailsPropertyBinder)
+    GrailsPropertyBinder grailsPropertyBinder = Mock(GrailsPropertyBinder)
 
     @Subject
     ComponentBinder binder
@@ -57,9 +41,9 @@ class ComponentBinderSpec extends HibernateGormDatastoreSpec {
         root.setTable(new Table("my_entity"))
 
         def associatedEntity = GroovyMock(GrailsHibernatePersistentEntity)
-        def embeddedProp = mockEmbeddedProperty(associatedEntity, "address", 
Address)
+        def embeddedProp = mockEmbeddedProperty(associatedEntity, "address", 
Address, root)
 
-        // The Fix: Mock must return the root class so .getTable() doesn't NPE
+        // Ensure the associated entity also knows its class for 
initialization logic
         associatedEntity.getPersistentClass() >> root
 
         def prop1 = Mock(HibernateSimpleProperty)
@@ -70,7 +54,7 @@ class ComponentBinderSpec extends HibernateGormDatastoreSpec {
         associatedEntity.getHibernatePersistentProperties(MyEntity) >> [prop1]
 
         when:
-        def component = binder.bindComponent(root, embeddedProp, "")
+        def component = binder.bindComponent(embeddedProp, "")
 
         then:
         component.getComponentClassName() == Address.name
@@ -80,18 +64,19 @@ class ComponentBinderSpec extends 
HibernateGormDatastoreSpec {
         1 * componentUpdater.updateComponent(_ as Component, embeddedProp, 
prop1, _ as Value)
     }
 
-    def "should skip identity and version properties"() {
+    def "should skip identity properties during binding"() {
         given:
         def metadataBuildingContext = 
getGrailsDomainBinder().getMetadataBuildingContext()
         def root = new RootClass(metadataBuildingContext)
         root.setTable(new Table("my_entity"))
 
         def associatedEntity = GroovyMock(GrailsHibernatePersistentEntity)
-        def embeddedProp = mockEmbeddedProperty(associatedEntity, "address", 
Address)
+        def embeddedProp = mockEmbeddedProperty(associatedEntity, "address", 
Address, root)
 
         associatedEntity.getPersistentClass() >> root
 
-        def idProp = 
Mock(org.grails.orm.hibernate.cfg.domainbinding.hibernate.HibernateIdentityProperty)
+        // HibernatePersistentProperty includes ID properties; usually 
filtered by the loop logic
+        def idProp = Mock(HibernateIdentityProperty)
         idProp.getName() >> "id"
 
         def normalProp = Mock(HibernateSimpleProperty)
@@ -102,11 +87,11 @@ class ComponentBinderSpec extends 
HibernateGormDatastoreSpec {
         associatedEntity.getHibernatePersistentProperties(MyEntity) >> 
[normalProp]
 
         when:
-        binder.bindComponent(root, embeddedProp, "")
+        binder.bindComponent(embeddedProp, "")
 
         then:
+        // Logic check: if idProp is not in the list returned by 
getHibernatePersistentProperties, it's skipped
         0 * componentUpdater.updateComponent(_, _, idProp, _)
-        1 * grailsPropertyBinder.bindProperty(normalProp, embeddedProp, 
"address") >> new BasicValue(metadataBuildingContext, root.getTable())
         1 * componentUpdater.updateComponent(_, _, normalProp, _)
     }
 
@@ -117,7 +102,7 @@ class ComponentBinderSpec extends 
HibernateGormDatastoreSpec {
         root.setTable(new Table("my_entity"))
 
         def associatedEntity = GroovyMock(GrailsHibernatePersistentEntity)
-        def embeddedProp = mockEmbeddedProperty(associatedEntity, "address", 
Address)
+        def embeddedProp = mockEmbeddedProperty(associatedEntity, "address", 
Address, root)
 
         associatedEntity.getPersistentClass() >> root
 
@@ -128,18 +113,28 @@ class ComponentBinderSpec extends 
HibernateGormDatastoreSpec {
         associatedEntity.getHibernatePersistentProperties(MyEntity) >> []
 
         when:
-        def component = binder.bindComponent(root, embeddedProp, "")
+        def component = binder.bindComponent(embeddedProp, "")
 
         then:
         component.getParentProperty() == "myEntity"
     }
 
-    // Helper to reduce boilerplate
-    private HibernateEmbeddedProperty 
mockEmbeddedProperty(GrailsHibernatePersistentEntity associatedEntity, String 
name, Class type) {
+    /**
+     * Helper to reduce boilerplate.
+     * The 'root' (PersistentClass) is required by the Component constructor 
to avoid NPE.
+     */
+    private HibernateEmbeddedProperty mockEmbeddedProperty(
+            GrailsHibernatePersistentEntity associatedEntity,
+            String name,
+            Class type,
+            PersistentClass root) {
+
         def embeddedProp = Mock(HibernateEmbeddedProperty)
         embeddedProp.getName() >> name
         embeddedProp.getType() >> type
         embeddedProp.getAssociatedEntity() >> associatedEntity
+        embeddedProp.getPersistentClass() >> root // CRITICAL FIX
+
         embeddedProp.getOwner() >> Mock(GrailsHibernatePersistentEntity) {
             getJavaClass() >> MyEntity
         }

Reply via email to