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

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

commit 80dc4f4bd559b6cdb5eefe2638bd0eb0115c411a
Author: Walter Duque de Estrada <[email protected]>
AuthorDate: Sun Sep 7 21:53:14 2025 -0500

    Created HibernateLegacyEnumType as a copy of the deprecated Hibernate 
EnumType
---
 .../orm/hibernate/HibernateLegacyEnumType.java     | 345 +++++++++++++++++++++
 .../orm/hibernate/cfg/GrailsDomainBinder.java      |   2 +-
 .../cfg/domainbinding/EnumTypeBinder.java          |  12 +-
 .../cfg/domainbinding/EnumTypeBinderSpec.groovy    |  12 +-
 4 files changed, 358 insertions(+), 13 deletions(-)

diff --git 
a/grails-data-hibernate6/core/src/main/groovy/org/grails/orm/hibernate/HibernateLegacyEnumType.java
 
b/grails-data-hibernate6/core/src/main/groovy/org/grails/orm/hibernate/HibernateLegacyEnumType.java
new file mode 100644
index 0000000000..f5554bc4d2
--- /dev/null
+++ 
b/grails-data-hibernate6/core/src/main/groovy/org/grails/orm/hibernate/HibernateLegacyEnumType.java
@@ -0,0 +1,345 @@
+/*
+ * Hibernate, Relational Persistence for Idiomatic Java
+ *
+ * License: GNU Lesser General Public License (LGPL), version 2.1 or later.
+ * See the lgpl.txt file in the root directory or 
<http://www.gnu.org/licenses/lgpl-2.1.html>.
+ */
+package org.grails.orm.hibernate;
+
+import java.io.Serializable;
+import java.lang.annotation.Annotation;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.Properties;
+
+import jakarta.persistence.EnumType;
+import jakarta.persistence.Enumerated;
+import jakarta.persistence.MapKeyEnumerated;
+
+import org.hibernate.AssertionFailure;
+import org.hibernate.HibernateException;
+import org.hibernate.annotations.Nationalized;
+import org.hibernate.dialect.Dialect;
+import org.hibernate.engine.spi.SessionFactoryImplementor;
+import org.hibernate.engine.spi.SharedSessionContractImplementor;
+import org.hibernate.internal.CoreLogging;
+import org.hibernate.internal.util.ReflectHelper;
+import org.hibernate.type.SqlTypes;
+import org.hibernate.type.descriptor.java.EnumJavaType;
+import org.hibernate.type.descriptor.java.JavaType;
+import org.hibernate.type.descriptor.jdbc.JdbcType;
+import org.hibernate.type.descriptor.jdbc.JdbcTypeIndicators;
+import org.hibernate.type.spi.TypeConfiguration;
+import org.hibernate.type.spi.TypeConfigurationAware;
+import org.hibernate.usertype.DynamicParameterizedType;
+import org.hibernate.usertype.EnhancedUserType;
+import org.hibernate.usertype.LoggableUserType;
+
+import org.jboss.logging.Logger;
+
+import static jakarta.persistence.EnumType.ORDINAL;
+import static jakarta.persistence.EnumType.STRING;
+import static 
org.hibernate.internal.util.config.ConfigurationHelper.getBoolean;
+
+/**
+ * Value type mapper for enumerations.
+ *
+ * @author Emmanuel Bernard
+ * @author Hardy Ferentschik
+ * @author Steve Ebersole
+ *
+ */
+public class HibernateLegacyEnumType<T extends Enum<T>>
+        implements EnhancedUserType<T>, DynamicParameterizedType, 
LoggableUserType, TypeConfigurationAware, Serializable {
+    private static final Logger LOG = CoreLogging.logger( EnumType.class );
+
+    public static final String ENUM = "enumClass";
+    public static final String NAMED = "useNamed";
+    public static final String TYPE = "type";
+
+    private Class<T> enumClass;
+
+    private boolean isOrdinal;
+    private JdbcType jdbcType;
+    private EnumJavaType<T> enumJavaType;
+
+    private TypeConfiguration typeConfiguration;
+
+    public HibernateLegacyEnumType() {
+    }
+
+    public Class<T> getEnumClass() {
+        return enumClass;
+    }
+
+    @Override
+    public JdbcType getJdbcType(TypeConfiguration typeConfiguration) {
+        return jdbcType;
+    }
+
+    /**
+     * <p>
+     * An instance of this class is "configured" by a call to {@link 
#setParameterValues},
+     * where configuration parameters are given as entries in a {@link 
Properties} object.
+     * There are two distinct ways an instance may be configured:
+     * <ul>
+     * <li>one for {@code hbm.xml}-based mapping, and
+     * <li>another for annotation-based or {@code orm.xml}-based mapping.
+     * </ul>
+     * <p>
+     * In the case of annotations or {@code orm.xml}, a {@link ParameterType} 
is passed to
+     * {@link #setParameterValues} under the key {@value #PARAMETER_TYPE}.
+     * <p>
+     * But in the case of {@code hbm.xml}, there are multiple parameters:
+     * <ul>
+     *     <li>
+     *         {@value #ENUM}, the name of the Java enumeration class.
+     *     </li>
+     *     <li>
+     *         {@value #NAMED}, specifies if the enum should be mapped by name.
+     *         Default is to map as ordinal.
+     *     </li>
+     *     <li>
+     *                         {@value #TYPE}, a JDBC type code (legacy 
alternative to {@value #NAMED}).
+     *     </li>
+     * </ul>
+     */
+    @Override
+    public void setParameterValues(Properties parameters) {
+        // IMPL NOTE: we handle 2 distinct cases here:
+        //             1) we are passed a ParameterType instance in the 
incoming Properties - generally
+        //                     speaking this indicates the annotation-binding 
case, and the passed ParameterType
+        //                     represents information about the attribute and 
annotation
+        //             2) we are not passed a ParameterType - generally this 
indicates a hbm.xml binding case.
+        final ParameterType reader = (ParameterType) parameters.get( 
PARAMETER_TYPE );
+
+        if ( parameters.containsKey( ENUM ) ) {
+            final String enumClassName = (String) parameters.get( ENUM );
+            try {
+                enumClass = (Class<T>) ReflectHelper.classForName( 
enumClassName, this.getClass() ).asSubclass( Enum.class );
+            }
+            catch ( ClassNotFoundException exception ) {
+                throw new HibernateException("Enum class not found: " + 
enumClassName, exception);
+            }
+        }
+        else if ( reader != null ) {
+            enumClass = (Class<T>) reader.getReturnedClass().asSubclass( 
Enum.class );
+        }
+
+        final JavaType<T> descriptor = 
typeConfiguration.getJavaTypeRegistry().getDescriptor( enumClass );
+        enumJavaType = (EnumJavaType<T>) descriptor;
+
+        if ( parameters.containsKey( TYPE ) ) {
+            int jdbcTypeCode = Integer.parseInt( (String) parameters.get( TYPE 
) );
+            jdbcType = typeConfiguration.getJdbcTypeRegistry().getDescriptor( 
jdbcTypeCode );
+            isOrdinal = jdbcType.isInteger()
+                    // Both, ENUM and NAMED_ENUM are treated like ordinal with 
respect to the ordering
+                    || jdbcType.getDefaultSqlTypeCode() == SqlTypes.ENUM
+                    || jdbcType.getDefaultSqlTypeCode() == SqlTypes.NAMED_ENUM;
+        }
+        else {
+            final LocalJdbcTypeIndicators indicators;
+            final Long columnLength = reader == null ? null : 
reader.getColumnLengths()[0];
+            if ( parameters.containsKey (NAMED ) ) {
+                indicators = new LocalJdbcTypeIndicators(
+                        // use ORDINAL as default for hbm.xml mappings
+                        getBoolean( NAMED, parameters ) ? STRING : ORDINAL,
+                        false,
+                        columnLength
+                );
+            }
+            else {
+                indicators = new LocalJdbcTypeIndicators(
+                        getEnumType( reader ),
+                        isNationalized( reader ),
+                        columnLength
+                );
+            }
+            jdbcType = descriptor.getRecommendedJdbcType( indicators );
+            isOrdinal = indicators.getEnumeratedType() != STRING;
+        }
+
+        if ( LOG.isDebugEnabled() ) {
+            LOG.debugf(
+                    "Using %s-based conversion for Enum %s",
+                    isOrdinal() ? "ORDINAL" : "NAMED",
+                    enumClass.getName()
+            );
+        }
+    }
+
+    private jakarta.persistence.EnumType getEnumType(ParameterType reader) {
+        if ( reader != null ) {
+            if ( reader.isPrimaryKey() ) {
+                final MapKeyEnumerated enumAnn = getAnnotation( 
reader.getAnnotationsMethod(), MapKeyEnumerated.class );
+                if ( enumAnn != null ) {
+                    return enumAnn.value();
+                }
+            }
+            final Enumerated enumAnn = getAnnotation( 
reader.getAnnotationsMethod(), Enumerated.class );
+            if ( enumAnn != null ) {
+                return enumAnn.value();
+            }
+        }
+        return ORDINAL;
+    }
+
+    private boolean isNationalized(ParameterType reader) {
+        return 
typeConfiguration.getCurrentBaseSqlTypeIndicators().isNationalized()
+                || reader!=null && getAnnotation( 
reader.getAnnotationsMethod(), Nationalized.class ) != null;
+    }
+
+    @SuppressWarnings("unchecked")
+    private <A extends Annotation> A getAnnotation(Annotation[] annotations, 
Class<A> annotationType) {
+        for ( Annotation annotation : annotations ) {
+            if ( annotationType.isInstance( annotation ) ) {
+                return (A) annotation;
+            }
+        }
+        return null;
+    }
+
+    @Override
+    public int getSqlType() {
+        verifyConfigured();
+        return jdbcType.getJdbcTypeCode();
+    }
+
+    @Override
+    public Class<T> returnedClass() {
+        return enumClass;
+    }
+
+    @Override
+    public boolean equals(T x, T y) throws HibernateException {
+        return x == y;
+    }
+
+    @Override
+    public int hashCode(T x) throws HibernateException {
+        return x == null ? 0 : x.hashCode();
+    }
+
+    @Override
+    public T nullSafeGet(ResultSet rs, int position, 
SharedSessionContractImplementor session, Object owner) throws SQLException {
+        verifyConfigured();
+        return jdbcType.getExtractor( enumJavaType ).extract( rs, position, 
session );
+    }
+
+    private void verifyConfigured() {
+        if ( enumJavaType == null ) {
+            throw new AssertionFailure("EnumType (" + enumClass.getName() + ") 
not properly, fully configured");
+        }
+    }
+
+    @Override
+    public void nullSafeSet(PreparedStatement st, T value, int index, 
SharedSessionContractImplementor session) throws HibernateException, 
SQLException {
+        verifyConfigured();
+        jdbcType.getBinder( enumJavaType ).bind( st, value, index, session );
+    }
+
+    @Override
+    public T deepCopy(T value) throws HibernateException {
+        return value;
+    }
+
+    @Override
+    public boolean isMutable() {
+        return false;
+    }
+
+    @Override
+    public Serializable disassemble(T value) throws HibernateException {
+        return value;
+    }
+
+    @Override
+    public T assemble(Serializable cached, Object owner) throws 
HibernateException {
+        return (T) cached;
+    }
+
+    @Override
+    public T replace(T original, T target, Object owner) throws 
HibernateException {
+        return original;
+    }
+
+    @Override
+    public TypeConfiguration getTypeConfiguration() {
+        return typeConfiguration;
+    }
+
+    @Override
+    public void setTypeConfiguration(TypeConfiguration typeConfiguration) {
+        this.typeConfiguration = typeConfiguration;
+    }
+
+    @Override
+    public String toSqlLiteral(T value) {
+        verifyConfigured();
+        return isOrdinal()
+                ? Integer.toString( value.ordinal() )
+                : "'" + value.name() + "'";
+    }
+
+    @Override
+    public String toString(T value) {
+        verifyConfigured();
+        return enumJavaType.toName( value );
+    }
+
+    @Override
+    public T fromStringValue(CharSequence sequence) {
+        verifyConfigured();
+        return enumJavaType.fromName( sequence.toString() );
+    }
+
+    @Override @SuppressWarnings("unchecked")
+    public String toLoggableString(Object value, SessionFactoryImplementor 
factory) {
+        verifyConfigured();
+        return enumJavaType.extractLoggableRepresentation( (T) value );
+    }
+
+    public boolean isOrdinal() {
+        verifyConfigured();
+        return isOrdinal;
+    }
+
+    private class LocalJdbcTypeIndicators implements JdbcTypeIndicators {
+        private final jakarta.persistence.EnumType enumType;
+        private final boolean nationalized;
+        private final Long columnLength;
+
+        private LocalJdbcTypeIndicators(jakarta.persistence.EnumType enumType, 
boolean nationalized, Long columnLength) {
+            this.enumType = enumType;
+            this.nationalized = nationalized;
+            this.columnLength = columnLength;
+        }
+
+        @Override
+        public TypeConfiguration getTypeConfiguration() {
+            return typeConfiguration;
+        }
+
+        @Override
+        public jakarta.persistence.EnumType getEnumeratedType() {
+            return enumType != null ? enumType : 
typeConfiguration.getCurrentBaseSqlTypeIndicators().getEnumeratedType();
+        }
+
+        @Override
+        public boolean isNationalized() {
+            return nationalized;
+        }
+
+
+        @Override
+        public long getColumnLength() {
+            return columnLength == null ? NO_COLUMN_LENGTH : columnLength;
+        }
+
+        @Override
+        public Dialect getDialect() {
+            return 
typeConfiguration.getCurrentBaseSqlTypeIndicators().getDialect();
+        }
+    }
+}
diff --git 
a/grails-data-hibernate6/core/src/main/groovy/org/grails/orm/hibernate/cfg/GrailsDomainBinder.java
 
b/grails-data-hibernate6/core/src/main/groovy/org/grails/orm/hibernate/cfg/GrailsDomainBinder.java
index 02f0e183f7..4585678f47 100644
--- 
a/grails-data-hibernate6/core/src/main/groovy/org/grails/orm/hibernate/cfg/GrailsDomainBinder.java
+++ 
b/grails-data-hibernate6/core/src/main/groovy/org/grails/orm/hibernate/cfg/GrailsDomainBinder.java
@@ -130,7 +130,7 @@ public class GrailsDomainBinder implements 
MetadataContributor {
     public static final String CASCADE_NONE = "none";
     private static final String BACKTICK = "`";
 
-    public static final String ENUM_TYPE_CLASS = "org.hibernate.type.EnumType";
+    public static final String ENUM_TYPE_CLASS = 
org.grails.orm.hibernate.HibernateLegacyEnumType.class.getName();
     public static final String ENUM_CLASS_PROP = "enumClass";
     private static final String ENUM_TYPE_PROP = "type";
     public static final String DEFAULT_ENUM_TYPE = "default";
diff --git 
a/grails-data-hibernate6/core/src/main/groovy/org/grails/orm/hibernate/cfg/domainbinding/EnumTypeBinder.java
 
b/grails-data-hibernate6/core/src/main/groovy/org/grails/orm/hibernate/cfg/domainbinding/EnumTypeBinder.java
index 9b98e8c915..6a2de0ee0e 100644
--- 
a/grails-data-hibernate6/core/src/main/groovy/org/grails/orm/hibernate/cfg/domainbinding/EnumTypeBinder.java
+++ 
b/grails-data-hibernate6/core/src/main/groovy/org/grails/orm/hibernate/cfg/domainbinding/EnumTypeBinder.java
@@ -10,7 +10,7 @@ import org.hibernate.MappingException;
 import org.hibernate.mapping.Column;
 import org.hibernate.mapping.SimpleValue;
 import org.hibernate.mapping.Table;
-import org.hibernate.type.EnumType;
+import org.grails.orm.hibernate.HibernateLegacyEnumType;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -51,13 +51,13 @@ public class EnumTypeBinder {
         } else {
             if (GrailsEnumType.DEFAULT.getType().equals(enumType) || 
GrailsEnumType.STRING.getType().equalsIgnoreCase(enumType)) {
                 simpleValue.setTypeName(ENUM_TYPE_CLASS);
-                enumProperties.put(EnumType.TYPE, 
String.valueOf(Types.VARCHAR));
-                enumProperties.put(EnumType.NAMED, Boolean.TRUE.toString());
+                enumProperties.put(HibernateLegacyEnumType.TYPE, 
String.valueOf(Types.VARCHAR));
+                enumProperties.put(HibernateLegacyEnumType.NAMED, 
Boolean.TRUE.toString());
             } else if 
(GrailsEnumType.ORDINAL.getType().equalsIgnoreCase(enumType)) {
                 simpleValue.setTypeName(ENUM_TYPE_CLASS);
-                enumProperties.put(EnumType.TYPE, 
String.valueOf(Types.INTEGER));
-                enumProperties.put(EnumType.NAMED, Boolean.FALSE.toString());
-            } else if (GrailsEnumType.ORDINAL.getType().equals(enumType)) {
+                enumProperties.put(HibernateLegacyEnumType.TYPE, 
String.valueOf(Types.INTEGER));
+                enumProperties.put(HibernateLegacyEnumType.NAMED, 
Boolean.FALSE.toString());
+            } else if (GrailsEnumType.IDENTITY.getType().equals(enumType)) {
                 simpleValue.setTypeName(IdentityEnumType.class.getName());
             } else {
                 throw new MappingException("Invalid enum type [" + enumType + 
"].");
diff --git 
a/grails-data-hibernate6/core/src/test/groovy/org/grails/orm/hibernate/cfg/domainbinding/EnumTypeBinderSpec.groovy
 
b/grails-data-hibernate6/core/src/test/groovy/org/grails/orm/hibernate/cfg/domainbinding/EnumTypeBinderSpec.groovy
index 3a5d305dbc..be7041668e 100644
--- 
a/grails-data-hibernate6/core/src/test/groovy/org/grails/orm/hibernate/cfg/domainbinding/EnumTypeBinderSpec.groovy
+++ 
b/grails-data-hibernate6/core/src/test/groovy/org/grails/orm/hibernate/cfg/domainbinding/EnumTypeBinderSpec.groovy
@@ -9,7 +9,7 @@ import org.hibernate.mapping.BasicValue
 import org.hibernate.mapping.Column
 import org.hibernate.mapping.Selectable
 import org.hibernate.mapping.Table
-import org.hibernate.type.EnumType
+import org.grails.orm.hibernate.HibernateLegacyEnumType
 import org.hibernate.usertype.UserType
 import spock.lang.Subject
 import spock.lang.Unroll
@@ -50,14 +50,14 @@ class EnumTypeBinderSpec extends HibernateGormDatastoreSpec 
{
 
         and: "the type parameters are configured correctly"
         def props = simpleValue.getTypeParameters()
-        (props.getProperty(EnumType.TYPE) == String.valueOf(expectedSqlType)) 
== typeExpected
-        (props.getProperty(EnumType.NAMED) == String.valueOf(namedExpected)) 
== namedIsExpected
+        (props.getProperty(HibernateLegacyEnumType.TYPE) == 
String.valueOf(expectedSqlType)) == typeExpected
+        (props.getProperty(HibernateLegacyEnumType.NAMED) == 
String.valueOf(namedExpected)) == namedIsExpected
 
         where:
         clazz | enumTypeMapping   | expectedHibernateType            | 
expectedSqlType   | typeExpected | namedExpected | namedIsExpected | nullable
-        Person01| "default"       | EnumType.class.getName()         | 
Types.VARCHAR     | true         | true          | true            | false
-        Person02|"string"         | EnumType.class.getName()         | 
Types.VARCHAR     | true         | true          | true            | true
-        Person03|"ordinal"        | EnumType.class.getName()         | 
Types.INTEGER     | true         | false         | true            | true
+        Person01| "default"       | HibernateLegacyEnumType.class.getName()    
     | Types.VARCHAR     | true         | true          | true            | 
false
+        Person02|"string"         | HibernateLegacyEnumType.class.getName()    
     | Types.VARCHAR     | true         | true          | true            | true
+        Person03|"ordinal"        | HibernateLegacyEnumType.class.getName()    
     | Types.INTEGER     | true         | false         | true            | true
         Person04|"identity"       | IdentityEnumType.class.getName() | null    
          | false        | null          | false           | false
         Person05|UserTypeEnumType | UserTypeEnumType.class.getName() | null    
          | false        | null          | false           | false
     }

Reply via email to