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 9441d2ed2605c82ac3b1317894f7e3f04e1e399e
Author: Walter Duque de Estrada <[email protected]>
AuthorDate: Mon Mar 2 08:48:21 2026 -0600

    Introduce HibernateEnumProperty marker interface; replace isEnumType() 
checks with instanceof
---
 .../domainbinding/binder/GrailsPropertyBinder.java | 18 +++-----
 .../cfg/domainbinding/binder/PropertyBinder.java   |  3 +-
 .../hibernate/HibernateCustomEnumProperty.java     | 40 +++++++++++++++++
 .../hibernate/HibernateEnumProperty.java           | 35 +++++++++++++++
 .../hibernate/HibernateMappingFactory.groovy       |  8 +++-
 .../hibernate/HibernateSimpleEnumProperty.java     | 35 +++++++++++++++
 .../util/PropertyFromValueCreator.java             |  3 +-
 .../gorm/specs/HibernateMappingFactorySpec.groovy  | 51 +++++++++++++++++++++-
 .../domainbinding/GrailsPropertyBinderSpec.groovy  | 10 ++++-
 9 files changed, 184 insertions(+), 19 deletions(-)

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 9bb67de3f4..63e5c95542 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
@@ -20,8 +20,7 @@ package org.grails.orm.hibernate.cfg.domainbinding.binder;
 
 import jakarta.annotation.Nonnull;
 import 
org.grails.orm.hibernate.cfg.domainbinding.hibernate.HibernateEmbeddedProperty;
-import 
org.grails.orm.hibernate.cfg.domainbinding.hibernate.HibernateManyToOneProperty;
-import 
org.grails.orm.hibernate.cfg.domainbinding.hibernate.HibernateOneToOneProperty;
+import 
org.grails.orm.hibernate.cfg.domainbinding.hibernate.HibernateEnumProperty;
 import 
org.grails.orm.hibernate.cfg.domainbinding.hibernate.HibernatePersistentProperty;
 import 
org.grails.orm.hibernate.cfg.domainbinding.hibernate.HibernateToManyProperty;
 import 
org.grails.orm.hibernate.cfg.domainbinding.hibernate.HibernateToOneProperty;
@@ -76,25 +75,20 @@ public class GrailsPropertyBinder {
     Value value = null;
 
     // 1. Create Value and apply binders (consolidated block)
-    if (currentGrailsProp.isEnumType()) {
-      // HibernateEnumTypeProperty
+    if (currentGrailsProp instanceof HibernateEnumProperty) {
       value =
           enumTypeBinder.bindEnumType(currentGrailsProp, 
currentGrailsProp.getType(), table, path);
-    } else if (currentGrailsProp instanceof HibernateOneToOneProperty 
oneToOne) {
-      // HibernateOneToOneProperty
-      if (oneToOne.isHibernateOneToOne()) {
+    } else if (currentGrailsProp instanceof HibernateToOneProperty toOne) {
+      if (toOne.isHibernateOneToOne()) {
         value =
             oneToOneBinder.bindOneToOne(
-                (org.grails.datastore.mapping.model.types.OneToOne) 
currentGrailsProp,
+                (org.grails.datastore.mapping.model.types.OneToOne) toOne,
                 persistentClass,
                 table,
                 path);
       } else {
-        value =
-            manyToOneBinder.bindManyToOne((HibernateToOneProperty) 
currentGrailsProp, table, path);
+        value = manyToOneBinder.bindManyToOne(toOne, table, path);
       }
-    } else if (currentGrailsProp instanceof HibernateManyToOneProperty 
manyToOne) {
-      value = manyToOneBinder.bindManyToOne(manyToOne, table, path);
     } else if (currentGrailsProp instanceof HibernateToManyProperty toMany
         && !currentGrailsProp.isSerializableType()) {
       // HibernateToManyProperty
diff --git 
a/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/cfg/domainbinding/binder/PropertyBinder.java
 
b/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/cfg/domainbinding/binder/PropertyBinder.java
index f1416f090d..f1bbf1d290 100644
--- 
a/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/cfg/domainbinding/binder/PropertyBinder.java
+++ 
b/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/cfg/domainbinding/binder/PropertyBinder.java
@@ -25,6 +25,7 @@ import org.grails.datastore.mapping.reflect.EntityReflector;
 import org.grails.orm.hibernate.access.TraitPropertyAccessStrategy;
 import org.grails.orm.hibernate.cfg.PropertyConfig;
 import 
org.grails.orm.hibernate.cfg.domainbinding.hibernate.HibernateAssociation;
+import 
org.grails.orm.hibernate.cfg.domainbinding.hibernate.HibernateEnumProperty;
 import 
org.grails.orm.hibernate.cfg.domainbinding.hibernate.HibernatePersistentProperty;
 import org.grails.orm.hibernate.cfg.domainbinding.util.CascadeBehaviorFetcher;
 import org.hibernate.boot.spi.AccessType;
@@ -84,7 +85,7 @@ public class PropertyBinder {
 
     prop.setOptional(persistentProperty.isNullable());
     if (persistentProperty instanceof Association<?> association
-        && !persistentProperty.isEnumType()) {
+        && !(persistentProperty instanceof HibernateEnumProperty)) {
       prop.setCascade(cascadeBehaviorFetcher.getCascadeBehaviour(association));
     }
 
diff --git 
a/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/cfg/domainbinding/hibernate/HibernateCustomEnumProperty.java
 
b/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/cfg/domainbinding/hibernate/HibernateCustomEnumProperty.java
new file mode 100644
index 0000000000..0ed1ac89b4
--- /dev/null
+++ 
b/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/cfg/domainbinding/hibernate/HibernateCustomEnumProperty.java
@@ -0,0 +1,40 @@
+/*
+ *  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.hibernate;
+
+import java.beans.PropertyDescriptor;
+import org.grails.datastore.mapping.engine.types.CustomTypeMarshaller;
+import org.grails.datastore.mapping.model.MappingContext;
+import org.grails.datastore.mapping.model.PersistentEntity;
+
+/**
+ * Hibernate custom property whose Java type is an enum backed by a registered 
{@link
+ * CustomTypeMarshaller}. Created by {@link 
HibernateMappingFactory#createCustom} when {@code
+ * pd.propertyType.isEnum()} is true and a matching marshaller is found.
+ */
+public class HibernateCustomEnumProperty extends HibernateCustomProperty
+    implements HibernateEnumProperty {
+  public HibernateCustomEnumProperty(
+      PersistentEntity entity,
+      MappingContext context,
+      PropertyDescriptor property,
+      CustomTypeMarshaller<?, ?, ?> customTypeMarshaller) {
+    super(entity, context, property, customTypeMarshaller);
+  }
+}
diff --git 
a/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/cfg/domainbinding/hibernate/HibernateEnumProperty.java
 
b/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/cfg/domainbinding/hibernate/HibernateEnumProperty.java
new file mode 100644
index 0000000000..a471622545
--- /dev/null
+++ 
b/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/cfg/domainbinding/hibernate/HibernateEnumProperty.java
@@ -0,0 +1,35 @@
+/*
+ *  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.hibernate;
+
+/**
+ * Marker interface for Hibernate persistent properties whose Java type is an 
enum.
+ *
+ * <p>Two concrete subtypes exist, corresponding to the two creation paths in 
{@link
+ * HibernateMappingFactory}:
+ *
+ * <ul>
+ *   <li>{@link HibernateSimpleEnumProperty} — plain enum with no custom type 
marshaller
+ *   <li>{@link HibernateCustomEnumProperty} — enum backed by a custom type 
marshaller
+ * </ul>
+ *
+ * <p>Use {@code instanceof HibernateEnumProperty} instead of {@code 
isEnumType()} to branch on
+ * enum properties at binding time.
+ */
+public interface HibernateEnumProperty extends HibernatePersistentProperty {}
diff --git 
a/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/cfg/domainbinding/hibernate/HibernateMappingFactory.groovy
 
b/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/cfg/domainbinding/hibernate/HibernateMappingFactory.groovy
index 2b70647979..dc1a80c224 100644
--- 
a/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/cfg/domainbinding/hibernate/HibernateMappingFactory.groovy
+++ 
b/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/cfg/domainbinding/hibernate/HibernateMappingFactory.groovy
@@ -80,7 +80,9 @@ class HibernateMappingFactory extends 
AbstractGormMappingFactory<Mapping, Proper
         if (customTypeMarshaller == null && propertyType.isEnum()) {
             customTypeMarshaller = findCustomType(context, Enum)
         }
-        HibernateCustomProperty custom = new HibernateCustomProperty(owner, 
context, pd, customTypeMarshaller)
+        HibernateCustomProperty custom = propertyType.isEnum()
+                ? new HibernateCustomEnumProperty(owner, context, pd, 
customTypeMarshaller)
+                : new HibernateCustomProperty(owner, context, pd, 
customTypeMarshaller)
         custom.setMapping(createPropertyMapping(custom, owner))
         custom
     }
@@ -88,7 +90,9 @@ class HibernateMappingFactory extends 
AbstractGormMappingFactory<Mapping, Proper
     @Override
     Simple<PropertyConfig> createSimple(
             PersistentEntity owner, MappingContext context, PropertyDescriptor 
pd) {
-        HibernateSimpleProperty simple = new HibernateSimpleProperty(owner, 
context, pd)
+        HibernateSimpleProperty simple = pd.propertyType.isEnum()
+                ? new HibernateSimpleEnumProperty(owner, context, pd)
+                : new HibernateSimpleProperty(owner, context, pd)
         simple.setMapping(createPropertyMapping(simple, owner))
         simple
     }
diff --git 
a/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/cfg/domainbinding/hibernate/HibernateSimpleEnumProperty.java
 
b/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/cfg/domainbinding/hibernate/HibernateSimpleEnumProperty.java
new file mode 100644
index 0000000000..3e0a09d221
--- /dev/null
+++ 
b/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/cfg/domainbinding/hibernate/HibernateSimpleEnumProperty.java
@@ -0,0 +1,35 @@
+/*
+ *  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.hibernate;
+
+import java.beans.PropertyDescriptor;
+import org.grails.datastore.mapping.model.MappingContext;
+import org.grails.datastore.mapping.model.PersistentEntity;
+
+/**
+ * Hibernate simple property whose Java type is an enum (no custom type 
marshaller). Created by
+ * {@link HibernateMappingFactory#createSimple} when {@code 
pd.propertyType.isEnum()} is true.
+ */
+public class HibernateSimpleEnumProperty extends HibernateSimpleProperty
+    implements HibernateEnumProperty {
+  public HibernateSimpleEnumProperty(
+      PersistentEntity entity, MappingContext context, PropertyDescriptor 
property) {
+    super(entity, context, property);
+  }
+}
diff --git 
a/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/cfg/domainbinding/util/PropertyFromValueCreator.java
 
b/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/cfg/domainbinding/util/PropertyFromValueCreator.java
index 916bd13837..cb6795e0d4 100644
--- 
a/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/cfg/domainbinding/util/PropertyFromValueCreator.java
+++ 
b/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/cfg/domainbinding/util/PropertyFromValueCreator.java
@@ -19,6 +19,7 @@
 package org.grails.orm.hibernate.cfg.domainbinding.util;
 
 import org.grails.orm.hibernate.cfg.domainbinding.binder.PropertyBinder;
+import 
org.grails.orm.hibernate.cfg.domainbinding.hibernate.HibernateEnumProperty;
 import 
org.grails.orm.hibernate.cfg.domainbinding.hibernate.HibernatePersistentProperty;
 import org.hibernate.mapping.Property;
 import org.hibernate.mapping.Value;
@@ -37,7 +38,7 @@ public class PropertyFromValueCreator {
 
   public Property createProperty(Value value, HibernatePersistentProperty 
grailsProperty) {
     // set type
-    if (!grailsProperty.isEnumType()) {
+    if (!(grailsProperty instanceof HibernateEnumProperty)) {
       value.setTypeUsingReflection(grailsProperty.getOwnerClassName(), 
grailsProperty.getName());
     }
 
diff --git 
a/grails-data-hibernate7/core/src/test/groovy/grails/gorm/specs/HibernateMappingFactorySpec.groovy
 
b/grails-data-hibernate7/core/src/test/groovy/grails/gorm/specs/HibernateMappingFactorySpec.groovy
index 66863795a0..3e9db5e60f 100644
--- 
a/grails-data-hibernate7/core/src/test/groovy/grails/gorm/specs/HibernateMappingFactorySpec.groovy
+++ 
b/grails-data-hibernate7/core/src/test/groovy/grails/gorm/specs/HibernateMappingFactorySpec.groovy
@@ -39,7 +39,7 @@ class HibernateMappingFactorySpec extends 
HibernateGormDatastoreSpec {
 
     def setupSpec() {
         manager.addAllDomainClasses([MappingFactoryBook, MappingFactoryAuthor, 
MappingFactoryTag,
-                                     MappingFactoryArticle])
+                                     MappingFactoryArticle, 
MappingFactoryEnumBook])
     }
 
     // --- unit-style tests (standalone factory) ---
@@ -167,6 +167,29 @@ class HibernateMappingFactorySpec extends 
HibernateGormDatastoreSpec {
         addrProp instanceof HibernateEmbeddedProperty
     }
 
+    void "createSimple creates HibernateSimpleEnumProperty for a plain enum 
field"() {
+        when:
+        PersistentEntity entity = 
mappingContext.getPersistentEntity(MappingFactoryEnumBook.name)
+        def statusProp = entity.persistentProperties.find { it.name == 
'status' }
+
+        then:
+        statusProp instanceof HibernateSimpleEnumProperty
+    }
+
+    void "createCustom creates HibernateCustomEnumProperty for an enum field 
with a registered marshaller"() {
+        given:
+        HibernateConnectionSourceSettings settings = new 
HibernateConnectionSourceSettings()
+        settings.custom.types = [new MappingFactoryEnumMarshaller()]
+        def ctx = new HibernateMappingContext(settings)
+        PersistentEntity entity = 
ctx.addPersistentEntity(MappingFactoryCustomEnumBook)
+
+        when:
+        def statusProp = entity.persistentProperties.find { it.name == 
'status' }
+
+        then:
+        statusProp instanceof HibernateCustomEnumProperty
+    }
+
     @Rollback
     void "factory-created entities can be persisted and retrieved"() {
         when:
@@ -234,3 +257,29 @@ class FactoryTypeMarshaller extends 
AbstractMappingAwareCustomTypeMarshaller {
     @Override
     protected Object readInternal(PersistentProperty property, String key, 
Object nativeSource) { nativeSource }
 }
+
+enum MappingFactoryBookStatus { AVAILABLE, CHECKED_OUT }
+
+@Entity
+class MappingFactoryEnumBook implements 
HibernateEntity<MappingFactoryEnumBook> {
+    String title
+    MappingFactoryBookStatus status
+}
+
+@Entity
+class MappingFactoryCustomEnumBook implements 
HibernateEntity<MappingFactoryCustomEnumBook> {
+    String title
+    MappingFactoryBookStatus status
+}
+
+class MappingFactoryEnumMarshaller extends 
AbstractMappingAwareCustomTypeMarshaller {
+    MappingFactoryEnumMarshaller() { super(MappingFactoryBookStatus) }
+
+    @Override
+    protected Object writeInternal(PersistentProperty property, String key, 
Object value, Object nativeTarget) { value?.name() }
+
+    @Override
+    protected Object readInternal(PersistentProperty property, String key, 
Object nativeSource) {
+        nativeSource ? 
MappingFactoryBookStatus.valueOf(nativeSource.toString()) : null
+    }
+}
diff --git 
a/grails-data-hibernate7/core/src/test/groovy/org/grails/orm/hibernate/cfg/domainbinding/GrailsPropertyBinderSpec.groovy
 
b/grails-data-hibernate7/core/src/test/groovy/org/grails/orm/hibernate/cfg/domainbinding/GrailsPropertyBinderSpec.groovy
index b76048a4d6..2989687ecb 100644
--- 
a/grails-data-hibernate7/core/src/test/groovy/org/grails/orm/hibernate/cfg/domainbinding/GrailsPropertyBinderSpec.groovy
+++ 
b/grails-data-hibernate7/core/src/test/groovy/org/grails/orm/hibernate/cfg/domainbinding/GrailsPropertyBinderSpec.groovy
@@ -18,6 +18,7 @@ import 
org.grails.orm.hibernate.cfg.domainbinding.hibernate.HibernateBasicProper
 import 
org.grails.orm.hibernate.cfg.domainbinding.hibernate.HibernateEmbeddedProperty
 import 
org.grails.orm.hibernate.cfg.domainbinding.hibernate.HibernateManyToOneProperty
 import 
org.grails.orm.hibernate.cfg.domainbinding.hibernate.HibernateOneToOneProperty
+import 
org.grails.orm.hibernate.cfg.domainbinding.hibernate.HibernateSimpleEnumProperty
 import 
org.grails.orm.hibernate.cfg.domainbinding.hibernate.HibernateSimpleProperty
 import org.grails.orm.hibernate.cfg.domainbinding.binder.CollectionBinder
 import org.grails.orm.hibernate.cfg.domainbinding.binder.ClassBinder
@@ -98,6 +99,12 @@ class GrailsPropertyBinderSpec extends 
HibernateGormDatastoreSpec {
         }
     }
 
+    abstract static class TestSimpleEnum extends HibernateSimpleEnumProperty {
+        TestSimpleEnum(PersistentEntity owner, MappingContext context, 
java.beans.PropertyDescriptor descriptor) {
+            super(owner, context, descriptor);
+        }
+    }
+
     private void setupProperty(PersistentProperty prop, String name, Mapping 
mapping, PersistentEntity owner) {
         prop.getName() >> name
         _ * prop.getOwner() >> owner
@@ -249,10 +256,9 @@ class GrailsPropertyBinderSpec extends 
HibernateGormDatastoreSpec {
         rootClass.setEntityName(persistentEntity.name)
         rootClass.setTable(collector.addTable(null, null, "ENUM_BOOK", null, 
false, binder.getMetadataBuildingContext()))
 
-        def statusProp = Mock(TestBasic)
+        def statusProp = Mock(TestSimpleEnum)
         setupProperty(statusProp, "status", new Mapping(), persistentEntity)
         statusProp.getType() >> java.util.concurrent.TimeUnit
-        statusProp.isEnumType() >> true
         statusProp.isHibernateOneToOne() >> false
         statusProp.isHibernateManyToOne() >> false
 

Reply via email to