From 488cdd9559515604e7095f548ce5922ebf8e2bbc Mon Sep 17 00:00:00 2001 From: Christian Beikov Date: Fri, 19 Apr 2024 12:07:29 +0200 Subject: [PATCH] HHH-17884 Fix the enum value sorting for EnumeratedType.STRING enums --- .../community/dialect/MySQLLegacyDialect.java | 3 + .../org/hibernate/dialect/MySQLDialect.java | 3 +- .../hibernate/dialect/MySQLEnumJdbcType.java | 72 +------------- .../dialect/PostgreSQLEnumJdbcType.java | 6 ++ .../converter/internal/EnumHelper.java | 14 ++- .../type/descriptor/jdbc/EnumJdbcType.java | 95 +++++++++++++++++++ .../enumerated/EnumeratedSmokeTest.java | 2 +- .../enumerated/ormXml/OrmXmlEnumTypeTest.java | 2 +- 8 files changed, 121 insertions(+), 76 deletions(-) create mode 100644 hibernate-core/src/main/java/org/hibernate/type/descriptor/jdbc/EnumJdbcType.java diff --git a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/MySQLLegacyDialect.java b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/MySQLLegacyDialect.java index 0d80444119ab..fce8b708a96c 100644 --- a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/MySQLLegacyDialect.java +++ b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/MySQLLegacyDialect.java @@ -67,6 +67,7 @@ import org.hibernate.type.SqlTypes; import org.hibernate.type.StandardBasicTypes; import org.hibernate.type.descriptor.java.JavaType; +import org.hibernate.type.descriptor.jdbc.EnumJdbcType; import org.hibernate.type.descriptor.jdbc.JdbcType; import org.hibernate.type.descriptor.jdbc.NullJdbcType; import org.hibernate.type.descriptor.jdbc.spi.JdbcTypeRegistry; @@ -651,6 +652,8 @@ public void contributeTypes(TypeContributions typeContributions, ServiceRegistry .getDescriptor( Object.class ) ) ); + + jdbcTypeRegistry.addDescriptor( EnumJdbcType.INSTANCE ); } @Override diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/MySQLDialect.java b/hibernate-core/src/main/java/org/hibernate/dialect/MySQLDialect.java index 2a065d37fa32..f3930f5a82cd 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/MySQLDialect.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/MySQLDialect.java @@ -70,6 +70,7 @@ import org.hibernate.type.SqlTypes; import org.hibernate.type.StandardBasicTypes; import org.hibernate.type.descriptor.java.JavaType; +import org.hibernate.type.descriptor.jdbc.EnumJdbcType; import org.hibernate.type.descriptor.jdbc.JdbcType; import org.hibernate.type.descriptor.jdbc.NullJdbcType; import org.hibernate.type.descriptor.jdbc.spi.JdbcTypeRegistry; @@ -671,7 +672,7 @@ public void contributeTypes(TypeContributions typeContributions, ServiceRegistry ) ); - jdbcTypeRegistry.addDescriptor( new MySQLEnumJdbcType() ); + jdbcTypeRegistry.addDescriptor( EnumJdbcType.INSTANCE ); } @Override diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/MySQLEnumJdbcType.java b/hibernate-core/src/main/java/org/hibernate/dialect/MySQLEnumJdbcType.java index b8f2837fe18a..cfb2d10a3807 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/MySQLEnumJdbcType.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/MySQLEnumJdbcType.java @@ -6,22 +6,7 @@ */ package org.hibernate.dialect; -import org.hibernate.type.descriptor.ValueBinder; -import org.hibernate.type.descriptor.ValueExtractor; -import org.hibernate.type.descriptor.WrapperOptions; -import org.hibernate.type.descriptor.java.JavaType; -import org.hibernate.type.descriptor.jdbc.BasicBinder; -import org.hibernate.type.descriptor.jdbc.BasicExtractor; -import org.hibernate.type.descriptor.jdbc.JdbcLiteralFormatter; -import org.hibernate.type.descriptor.jdbc.JdbcType; -import org.hibernate.type.descriptor.jdbc.internal.JdbcLiteralFormatterCharacterData; - -import java.sql.CallableStatement; -import java.sql.PreparedStatement; -import java.sql.ResultSet; -import java.sql.SQLException; - -import static org.hibernate.type.SqlTypes.ENUM; +import org.hibernate.type.descriptor.jdbc.EnumJdbcType; /** * Represents an {@code enum} type on MySQL. @@ -31,60 +16,11 @@ * * @see org.hibernate.type.SqlTypes#ENUM * @see MySQLDialect#getEnumTypeDeclaration(String, String[]) + * @deprecated Use {@link EnumJdbcType} instead * * @author Gavin King */ -public class MySQLEnumJdbcType implements JdbcType { - - @Override - public int getJdbcTypeCode() { - return ENUM; - } - - @Override - public JdbcLiteralFormatter getJdbcLiteralFormatter(JavaType javaType) { - return new JdbcLiteralFormatterCharacterData<>( javaType ); - } - - @Override - public String getFriendlyName() { - return "ENUM"; - } - - @Override - public ValueBinder getBinder(JavaType javaType) { - return new BasicBinder<>( javaType, this ) { - @Override - protected void doBind(PreparedStatement st, X value, int index, WrapperOptions options) - throws SQLException { - st.setString( index, getJavaType().unwrap( value, String.class, options ) ); - } - - @Override - protected void doBind(CallableStatement st, X value, String name, WrapperOptions options) - throws SQLException { - st.setString( name, getJavaType().unwrap( value, String.class, options ) ); - } - }; - } - - @Override - public ValueExtractor getExtractor(JavaType javaType) { - return new BasicExtractor<>( javaType, this ) { - @Override - protected X doExtract(ResultSet rs, int paramIndex, WrapperOptions options) throws SQLException { - return getJavaType().wrap( rs.getString( paramIndex ), options ); - } - - @Override - protected X doExtract(CallableStatement statement, int index, WrapperOptions options) throws SQLException { - return getJavaType().wrap( statement.getString( index ), options ); - } +@Deprecated +public class MySQLEnumJdbcType extends EnumJdbcType { - @Override - protected X doExtract(CallableStatement statement, String name, WrapperOptions options) throws SQLException { - return getJavaType().wrap( statement.getString( name ), options ); - } - }; - } } diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/PostgreSQLEnumJdbcType.java b/hibernate-core/src/main/java/org/hibernate/dialect/PostgreSQLEnumJdbcType.java index 18ef89b89e9b..ee10f5fcfc28 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/PostgreSQLEnumJdbcType.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/PostgreSQLEnumJdbcType.java @@ -28,6 +28,7 @@ import static java.util.Arrays.sort; import static java.util.Collections.emptySet; import static org.hibernate.type.SqlTypes.NAMED_ENUM; +import static org.hibernate.type.SqlTypes.OTHER; import static org.hibernate.type.descriptor.converter.internal.EnumHelper.getEnumeratedValues; /** @@ -50,6 +51,11 @@ public class PostgreSQLEnumJdbcType implements JdbcType { @Override public int getJdbcTypeCode() { + return OTHER; + } + + @Override + public int getDefaultSqlTypeCode() { return NAMED_ENUM; } diff --git a/hibernate-core/src/main/java/org/hibernate/type/descriptor/converter/internal/EnumHelper.java b/hibernate-core/src/main/java/org/hibernate/type/descriptor/converter/internal/EnumHelper.java index 210cfd28e987..718beef63fca 100644 --- a/hibernate-core/src/main/java/org/hibernate/type/descriptor/converter/internal/EnumHelper.java +++ b/hibernate-core/src/main/java/org/hibernate/type/descriptor/converter/internal/EnumHelper.java @@ -9,6 +9,7 @@ import java.util.Arrays; import org.hibernate.type.BasicType; +import org.hibernate.type.SqlTypes; import org.hibernate.type.Type; import org.hibernate.type.descriptor.jdbc.JdbcType; @@ -24,11 +25,14 @@ public static String[] getEnumeratedValues(Class javaType, JdbcType jdbcType) //noinspection unchecked final Class> enumClass = (Class>) javaType; final String[] enumValues; - if ( jdbcType.isString() ) { - enumValues = getSortedEnumeratedValues( enumClass ); - } - else { - enumValues = getEnumeratedValues( enumClass ); + switch ( jdbcType.getDefaultSqlTypeCode() ) { + case SqlTypes.ENUM: + case SqlTypes.NAMED_ENUM: + enumValues = getSortedEnumeratedValues( enumClass ); + break; + default: + enumValues = getEnumeratedValues( enumClass ); + break; } return enumValues; } diff --git a/hibernate-core/src/main/java/org/hibernate/type/descriptor/jdbc/EnumJdbcType.java b/hibernate-core/src/main/java/org/hibernate/type/descriptor/jdbc/EnumJdbcType.java new file mode 100644 index 000000000000..2ab7b3d6d3cc --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/type/descriptor/jdbc/EnumJdbcType.java @@ -0,0 +1,95 @@ +/* + * 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 . + */ +package org.hibernate.type.descriptor.jdbc; + +import java.sql.CallableStatement; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; + +import org.hibernate.dialect.MySQLDialect; +import org.hibernate.type.descriptor.ValueBinder; +import org.hibernate.type.descriptor.ValueExtractor; +import org.hibernate.type.descriptor.WrapperOptions; +import org.hibernate.type.descriptor.java.JavaType; +import org.hibernate.type.descriptor.jdbc.internal.JdbcLiteralFormatterCharacterData; + +import static org.hibernate.type.SqlTypes.ENUM; +import static org.hibernate.type.SqlTypes.VARCHAR; + +/** + * Represents an {@code enum} type for databases like MySQL and H2. + *

+ * Hibernate will automatically use this for enums mapped + * as {@link jakarta.persistence.EnumType#STRING}. + * + * @see org.hibernate.type.SqlTypes#ENUM + * @see MySQLDialect#getEnumTypeDeclaration(String, String[]) + * + * @author Gavin King + */ +public class EnumJdbcType implements JdbcType { + + public static final EnumJdbcType INSTANCE = new EnumJdbcType(); + + @Override + public int getJdbcTypeCode() { + return VARCHAR; + } + + @Override + public int getDefaultSqlTypeCode() { + return ENUM; + } + + @Override + public JdbcLiteralFormatter getJdbcLiteralFormatter(JavaType javaType) { + return new JdbcLiteralFormatterCharacterData<>( javaType ); + } + + @Override + public String getFriendlyName() { + return "ENUM"; + } + + @Override + public ValueBinder getBinder(JavaType javaType) { + return new BasicBinder<>( javaType, this ) { + @Override + protected void doBind(PreparedStatement st, X value, int index, WrapperOptions options) + throws SQLException { + st.setString( index, getJavaType().unwrap( value, String.class, options ) ); + } + + @Override + protected void doBind(CallableStatement st, X value, String name, WrapperOptions options) + throws SQLException { + st.setString( name, getJavaType().unwrap( value, String.class, options ) ); + } + }; + } + + @Override + public ValueExtractor getExtractor(JavaType javaType) { + return new BasicExtractor<>( javaType, this ) { + @Override + protected X doExtract(ResultSet rs, int paramIndex, WrapperOptions options) throws SQLException { + return getJavaType().wrap( rs.getString( paramIndex ), options ); + } + + @Override + protected X doExtract(CallableStatement statement, int index, WrapperOptions options) throws SQLException { + return getJavaType().wrap( statement.getString( index ), options ); + } + + @Override + protected X doExtract(CallableStatement statement, String name, WrapperOptions options) throws SQLException { + return getJavaType().wrap( statement.getString( name ), options ); + } + }; + } +} diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/annotations/enumerated/EnumeratedSmokeTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/annotations/enumerated/EnumeratedSmokeTest.java index b21b4ed20e50..89ab385e44bd 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/annotations/enumerated/EnumeratedSmokeTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/annotations/enumerated/EnumeratedSmokeTest.java @@ -67,7 +67,7 @@ private void validateEnumMapping(JdbcTypeRegistry jdbcRegistry, Property propert } else { // Assertions.assertThat( valueConverter ).isInstanceOf( NamedEnumValueConverter.class ); - Assertions.assertThat(jdbcType.isString() || jdbcType.getJdbcTypeCode() == SqlTypes.ENUM).isTrue(); + Assertions.assertThat( jdbcType.isString() || jdbcType.getDefaultSqlTypeCode() == SqlTypes.ENUM ).isTrue(); } } diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/annotations/enumerated/ormXml/OrmXmlEnumTypeTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/annotations/enumerated/ormXml/OrmXmlEnumTypeTest.java index a0780d592327..2fe18a300bee 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/annotations/enumerated/ormXml/OrmXmlEnumTypeTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/annotations/enumerated/ormXml/OrmXmlEnumTypeTest.java @@ -48,7 +48,7 @@ public void testOrmXmlDefinedEnumType() { BasicTypeImpl enumMapping = ExtraAssertions.assertTyping( BasicTypeImpl.class, bindingPropertyType ); assertEquals( jdbcTypeRegistry.getDescriptor( jdbcTypeRegistry.hasRegisteredDescriptor( ENUM ) ? ENUM : VARCHAR ), - jdbcTypeRegistry.getDescriptor( enumMapping.getJdbcType().getJdbcTypeCode() ) + jdbcTypeRegistry.getDescriptor( enumMapping.getJdbcType().getDefaultSqlTypeCode() ) ); } finally {