From 94f17a92e02f124a8423e16e6e578f354f2e42fb Mon Sep 17 00:00:00 2001 From: Christian Beikov Date: Thu, 28 Mar 2024 13:35:56 +0100 Subject: [PATCH] HHH-17904 Introduce config property to enable native enum type --- .../internal/SessionFactoryOptionsBuilder.java | 9 ++++++++- .../boot/model/internal/BasicValueBinder.java | 5 +++++ .../process/internal/VersionResolution.java | 5 +++++ ...bstractDelegatingSessionFactoryOptions.java | 5 +++++ .../boot/spi/MetadataBuildingContext.java | 18 ++++++++++++++++++ .../boot/spi/SessionFactoryOptions.java | 2 ++ .../org/hibernate/cfg/MappingSettings.java | 15 +++++++++++++++ .../java/org/hibernate/mapping/BasicValue.java | 5 +++++ .../type/descriptor/java/EnumJavaType.java | 7 ++++--- .../jdbc/DelegatingJdbcTypeIndicators.java | 5 +++++ .../descriptor/jdbc/JdbcTypeIndicators.java | 7 +++++++ .../hibernate/type/spi/TypeConfiguration.java | 7 +++++++ .../mapping/converted/enums/EnumTypeTest.java | 8 ++++++++ .../enums/UnspecifiedEnumTypeTest.java | 1 + .../customtype/UnspecifiedEnumTypeTest.java | 1 + .../envers/integration/collection/EnumSet.java | 9 +++++++++ .../integration/customtype/EnumTypeTest.java | 9 +++++++++ .../validation/MockSessionFactory.java | 5 +++++ 18 files changed, 119 insertions(+), 4 deletions(-) diff --git a/hibernate-core/src/main/java/org/hibernate/boot/internal/SessionFactoryOptionsBuilder.java b/hibernate-core/src/main/java/org/hibernate/boot/internal/SessionFactoryOptionsBuilder.java index 99a54a2842..c0a914dd3a 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/internal/SessionFactoryOptionsBuilder.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/internal/SessionFactoryOptionsBuilder.java @@ -222,7 +222,8 @@ public class SessionFactoryOptionsBuilder implements SessionFactoryOptions { private final SqmTranslatorFactory sqmTranslatorFactory; private final Boolean useOfJdbcNamedParametersEnabled; private boolean namedQueryStartupCheckingEnabled; - private boolean preferJavaTimeJdbcTypes; + private final boolean preferJavaTimeJdbcTypes; + private final boolean preferNativeEnumTypes; private final int preferredSqlTypeCodeForBoolean; private final int preferredSqlTypeCodeForDuration; private final int preferredSqlTypeCodeForUuid; @@ -445,6 +446,7 @@ public class SessionFactoryOptionsBuilder implements SessionFactoryOptions { this.namedQueryStartupCheckingEnabled = configurationService.getSetting( QUERY_STARTUP_CHECKING, BOOLEAN, true ); this.preferJavaTimeJdbcTypes = MetadataBuildingContext.isPreferJavaTimeJdbcTypesEnabled( configurationService ); + this.preferNativeEnumTypes = MetadataBuildingContext.isPreferNativeEnumTypesEnabled( configurationService ); this.preferredSqlTypeCodeForBoolean = ConfigurationHelper.getPreferredSqlTypeCodeForBoolean( serviceRegistry ); this.preferredSqlTypeCodeForDuration = ConfigurationHelper.getPreferredSqlTypeCodeForDuration( serviceRegistry ); this.preferredSqlTypeCodeForUuid = ConfigurationHelper.getPreferredSqlTypeCodeForUuid( serviceRegistry ); @@ -1288,6 +1290,11 @@ public class SessionFactoryOptionsBuilder implements SessionFactoryOptions { return preferJavaTimeJdbcTypes; } + @Override + public boolean isPreferNativeEnumTypesEnabled() { + return preferNativeEnumTypes; + } + @Override public FormatMapper getJsonFormatMapper() { return jsonFormatMapper; diff --git a/hibernate-core/src/main/java/org/hibernate/boot/model/internal/BasicValueBinder.java b/hibernate-core/src/main/java/org/hibernate/boot/model/internal/BasicValueBinder.java index 006a01a8d7..b54af8adf9 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/model/internal/BasicValueBinder.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/model/internal/BasicValueBinder.java @@ -223,6 +223,11 @@ public class BasicValueBinder implements JdbcTypeIndicators { return buildingContext.isPreferJavaTimeJdbcTypesEnabled(); } + @Override + public boolean isPreferNativeEnumTypesEnabled() { + return buildingContext.isPreferNativeEnumTypesEnabled(); + } + @Override public int getPreferredSqlTypeCodeForBoolean() { return resolveJdbcTypeCode( buildingContext.getPreferredSqlTypeCodeForBoolean() ); diff --git a/hibernate-core/src/main/java/org/hibernate/boot/model/process/internal/VersionResolution.java b/hibernate-core/src/main/java/org/hibernate/boot/model/process/internal/VersionResolution.java index c67278b23f..6cd40dc201 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/model/process/internal/VersionResolution.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/model/process/internal/VersionResolution.java @@ -65,6 +65,11 @@ public class VersionResolution implements BasicValue.Resolution { return context.isPreferJavaTimeJdbcTypesEnabled(); } + @Override + public boolean isPreferNativeEnumTypesEnabled() { + return context.isPreferNativeEnumTypesEnabled(); + } + @Override public TimeZoneStorageStrategy getDefaultTimeZoneStorageStrategy() { return BasicValue.timeZoneStorageStrategy( timeZoneStorageType, context ); diff --git a/hibernate-core/src/main/java/org/hibernate/boot/spi/AbstractDelegatingSessionFactoryOptions.java b/hibernate-core/src/main/java/org/hibernate/boot/spi/AbstractDelegatingSessionFactoryOptions.java index 38948d2c20..b69006d88f 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/spi/AbstractDelegatingSessionFactoryOptions.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/spi/AbstractDelegatingSessionFactoryOptions.java @@ -493,6 +493,11 @@ public class AbstractDelegatingSessionFactoryOptions implements SessionFactoryOp return delegate.isPreferJavaTimeJdbcTypesEnabled(); } + @Override + public boolean isPreferNativeEnumTypesEnabled() { + return delegate.isPreferNativeEnumTypesEnabled(); + } + @Override public FormatMapper getJsonFormatMapper() { return delegate.getJsonFormatMapper(); diff --git a/hibernate-core/src/main/java/org/hibernate/boot/spi/MetadataBuildingContext.java b/hibernate-core/src/main/java/org/hibernate/boot/spi/MetadataBuildingContext.java index f523aa8d4e..1872aaf7e2 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/spi/MetadataBuildingContext.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/spi/MetadataBuildingContext.java @@ -85,10 +85,19 @@ public interface MetadataBuildingContext { return isPreferJavaTimeJdbcTypesEnabled( getBootstrapContext().getServiceRegistry() ); } + @Incubating + default boolean isPreferNativeEnumTypesEnabled() { + return isPreferNativeEnumTypesEnabled( getBootstrapContext().getServiceRegistry() ); + } + static boolean isPreferJavaTimeJdbcTypesEnabled(ServiceRegistry serviceRegistry) { return isPreferJavaTimeJdbcTypesEnabled( serviceRegistry.requireService( ConfigurationService.class ) ); } + static boolean isPreferNativeEnumTypesEnabled(ServiceRegistry serviceRegistry) { + return isPreferNativeEnumTypesEnabled( serviceRegistry.requireService( ConfigurationService.class ) ); + } + static boolean isPreferJavaTimeJdbcTypesEnabled(ConfigurationService configurationService) { return ConfigurationHelper.getBoolean( MappingSettings.PREFER_JAVA_TYPE_JDBC_TYPES, @@ -98,6 +107,15 @@ public interface MetadataBuildingContext { ); } + static boolean isPreferNativeEnumTypesEnabled(ConfigurationService configurationService) { + return ConfigurationHelper.getBoolean( + MappingSettings.PREFER_NATIVE_ENUM_TYPES, + configurationService.getSettings(), + // todo: switch to true with HHH-17905 + false + ); + } + TypeDefinitionRegistry getTypeDefinitionRegistry(); /** diff --git a/hibernate-core/src/main/java/org/hibernate/boot/spi/SessionFactoryOptions.java b/hibernate-core/src/main/java/org/hibernate/boot/spi/SessionFactoryOptions.java index 8d71deb4be..a1501a381d 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/spi/SessionFactoryOptions.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/spi/SessionFactoryOptions.java @@ -345,6 +345,8 @@ public interface SessionFactoryOptions extends QueryEngineOptions { boolean isPreferJavaTimeJdbcTypesEnabled(); + boolean isPreferNativeEnumTypesEnabled(); + /** * The format mapper to use for serializing/deserializing JSON data. * diff --git a/hibernate-core/src/main/java/org/hibernate/cfg/MappingSettings.java b/hibernate-core/src/main/java/org/hibernate/cfg/MappingSettings.java index 0e2342fb12..f53f5430ad 100644 --- a/hibernate-core/src/main/java/org/hibernate/cfg/MappingSettings.java +++ b/hibernate-core/src/main/java/org/hibernate/cfg/MappingSettings.java @@ -242,6 +242,21 @@ public interface MappingSettings { @Incubating String PREFER_JAVA_TYPE_JDBC_TYPES = "hibernate.type.prefer_java_type_jdbc_types"; + /** + * Indicates whether to prefer using SQL enums and the respective special JDBC types for binding/extracting + * of values. + *

+ * Used to set the value across the entire system as opposed to scattered, individual + * {@linkplain org.hibernate.annotations.JdbcTypeCode} and {@linkplain org.hibernate.annotations.JdbcType} + * naming specific {@linkplain org.hibernate.type.descriptor.jdbc.JdbcType} implementations. + * + * @settingDefault false + * + * @since 6.5 + */ + @Incubating + String PREFER_NATIVE_ENUM_TYPES = "hibernate.type.prefer_native_enum_types"; + /** * Specifies a {@link org.hibernate.type.format.FormatMapper} used for JSON * serialization and deserialization, either: diff --git a/hibernate-core/src/main/java/org/hibernate/mapping/BasicValue.java b/hibernate-core/src/main/java/org/hibernate/mapping/BasicValue.java index 8930c291a0..442610b929 100644 --- a/hibernate-core/src/main/java/org/hibernate/mapping/BasicValue.java +++ b/hibernate-core/src/main/java/org/hibernate/mapping/BasicValue.java @@ -1111,6 +1111,11 @@ public class BasicValue extends SimpleValue implements JdbcTypeIndicators, Resol return getBuildingContext().isPreferJavaTimeJdbcTypesEnabled(); } + @Override + public boolean isPreferNativeEnumTypesEnabled() { + return getBuildingContext().isPreferNativeEnumTypesEnabled(); + } + @Override public Object accept(ValueVisitor visitor) { return visitor.accept(this); diff --git a/hibernate-core/src/main/java/org/hibernate/type/descriptor/java/EnumJavaType.java b/hibernate-core/src/main/java/org/hibernate/type/descriptor/java/EnumJavaType.java index 56559dd533..84c47a18cf 100644 --- a/hibernate-core/src/main/java/org/hibernate/type/descriptor/java/EnumJavaType.java +++ b/hibernate-core/src/main/java/org/hibernate/type/descriptor/java/EnumJavaType.java @@ -40,13 +40,14 @@ public class EnumJavaType> extends AbstractClassJavaType { public JdbcType getRecommendedJdbcType(JdbcTypeIndicators context) { final JdbcTypeRegistry jdbcTypeRegistry = context.getTypeConfiguration().getJdbcTypeRegistry(); final EnumType type = context.getEnumeratedType(); + final boolean preferNativeEnumTypesEnabled = context.isPreferNativeEnumTypesEnabled(); int sqlType; switch ( type == null ? ORDINAL : type ) { case ORDINAL: - if ( jdbcTypeRegistry.hasRegisteredDescriptor( ENUM ) ) { + if ( preferNativeEnumTypesEnabled && jdbcTypeRegistry.hasRegisteredDescriptor( ENUM ) ) { sqlType = ENUM; } - else if ( jdbcTypeRegistry.hasRegisteredDescriptor( NAMED_ENUM ) ) { + else if ( preferNativeEnumTypesEnabled && jdbcTypeRegistry.hasRegisteredDescriptor( NAMED_ENUM ) ) { sqlType = NAMED_ENUM; } else { @@ -57,7 +58,7 @@ public class EnumJavaType> extends AbstractClassJavaType { if ( jdbcTypeRegistry.hasRegisteredDescriptor( ENUM ) ) { sqlType = ENUM; } - else if ( jdbcTypeRegistry.hasRegisteredDescriptor( NAMED_ENUM ) ) { + else if ( preferNativeEnumTypesEnabled && jdbcTypeRegistry.hasRegisteredDescriptor( NAMED_ENUM ) ) { sqlType = NAMED_ENUM; } else if ( context.getColumnLength() == 1 ) { diff --git a/hibernate-core/src/main/java/org/hibernate/type/descriptor/jdbc/DelegatingJdbcTypeIndicators.java b/hibernate-core/src/main/java/org/hibernate/type/descriptor/jdbc/DelegatingJdbcTypeIndicators.java index 2ab719f2db..ed7adc42a0 100644 --- a/hibernate-core/src/main/java/org/hibernate/type/descriptor/jdbc/DelegatingJdbcTypeIndicators.java +++ b/hibernate-core/src/main/java/org/hibernate/type/descriptor/jdbc/DelegatingJdbcTypeIndicators.java @@ -47,6 +47,11 @@ public class DelegatingJdbcTypeIndicators implements JdbcTypeIndicators { return delegate.isPreferJavaTimeJdbcTypesEnabled(); } + @Override + public boolean isPreferNativeEnumTypesEnabled() { + return delegate.isPreferNativeEnumTypesEnabled(); + } + @Override public int getPreferredSqlTypeCodeForBoolean() { return delegate.getPreferredSqlTypeCodeForBoolean(); diff --git a/hibernate-core/src/main/java/org/hibernate/type/descriptor/jdbc/JdbcTypeIndicators.java b/hibernate-core/src/main/java/org/hibernate/type/descriptor/jdbc/JdbcTypeIndicators.java index 5e762fb342..0c59937e33 100644 --- a/hibernate-core/src/main/java/org/hibernate/type/descriptor/jdbc/JdbcTypeIndicators.java +++ b/hibernate-core/src/main/java/org/hibernate/type/descriptor/jdbc/JdbcTypeIndicators.java @@ -76,6 +76,13 @@ public interface JdbcTypeIndicators { return getCurrentBaseSqlTypeIndicators().isPreferJavaTimeJdbcTypesEnabled(); } + /** + * @see org.hibernate.cfg.MappingSettings#PREFER_NATIVE_ENUM_TYPES + */ + default boolean isPreferNativeEnumTypesEnabled() { + return getCurrentBaseSqlTypeIndicators().isPreferNativeEnumTypesEnabled(); + } + /** * When mapping a boolean type to the database what is the preferred SQL type code to use? *

diff --git a/hibernate-core/src/main/java/org/hibernate/type/spi/TypeConfiguration.java b/hibernate-core/src/main/java/org/hibernate/type/spi/TypeConfiguration.java index 8293e02966..585e61fac1 100644 --- a/hibernate-core/src/main/java/org/hibernate/type/spi/TypeConfiguration.java +++ b/hibernate-core/src/main/java/org/hibernate/type/spi/TypeConfiguration.java @@ -429,6 +429,13 @@ public class TypeConfiguration implements SessionFactoryObserver, Serializable { : sessionFactory.getSessionFactoryOptions().isPreferJavaTimeJdbcTypesEnabled(); } + @Override + public boolean isPreferNativeEnumTypesEnabled() { + return sessionFactory == null + ? metadataBuildingContext.isPreferNativeEnumTypesEnabled() + : sessionFactory.getSessionFactoryOptions().isPreferNativeEnumTypesEnabled(); + } + @Override public TimeZoneStorageStrategy getDefaultTimeZoneStorageStrategy() { return sessionFactory == null diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/converted/enums/EnumTypeTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/converted/enums/EnumTypeTest.java index bc4b2a28c8..046963631c 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/converted/enums/EnumTypeTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/converted/enums/EnumTypeTest.java @@ -11,6 +11,8 @@ import jakarta.persistence.criteria.CriteriaQuery; import jakarta.persistence.criteria.Root; import org.hibernate.Session; +import org.hibernate.cfg.Configuration; +import org.hibernate.cfg.Environment; import org.hibernate.internal.CoreMessageLogger; import org.hibernate.type.descriptor.JdbcBindingLogging; import org.hibernate.type.descriptor.JdbcExtractingLogging; @@ -60,6 +62,12 @@ public class EnumTypeTest extends BaseCoreFunctionalTestCase { return new String[] { "org/hibernate/orm/test/mapping/converted/enums/Person.hbm.xml" }; } + @Override + protected void configure(Configuration configuration) { + super.configure( configuration ); + configuration.setProperty( Environment.PREFER_NATIVE_ENUM_TYPES, "false" ); + } + @Override protected void prepareTest() { doInHibernate( this::sessionFactory, s -> { diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/converted/enums/UnspecifiedEnumTypeTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/converted/enums/UnspecifiedEnumTypeTest.java index a3138fb049..d487ce2dc6 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/converted/enums/UnspecifiedEnumTypeTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/converted/enums/UnspecifiedEnumTypeTest.java @@ -42,6 +42,7 @@ public class UnspecifiedEnumTypeTest extends BaseCoreFunctionalTestCase { protected void configure(Configuration configuration) { super.configure( configuration ); configuration.setProperty( Environment.HBM2DDL_AUTO, "" ); + configuration.setProperty( Environment.PREFER_NATIVE_ENUM_TYPES, "false" ); } @Before diff --git a/hibernate-envers/src/test/java/org/hibernate/envers/test/integration/customtype/UnspecifiedEnumTypeTest.java b/hibernate-envers/src/test/java/org/hibernate/envers/test/integration/customtype/UnspecifiedEnumTypeTest.java index fe1291be4a..3feb5a42ea 100644 --- a/hibernate-envers/src/test/java/org/hibernate/envers/test/integration/customtype/UnspecifiedEnumTypeTest.java +++ b/hibernate-envers/src/test/java/org/hibernate/envers/test/integration/customtype/UnspecifiedEnumTypeTest.java @@ -43,6 +43,7 @@ public class UnspecifiedEnumTypeTest extends BaseEnversFunctionalTestCase { settings.put( AvailableSettings.SHOW_SQL, "true" ); settings.put( AvailableSettings.FORMAT_SQL, "true" ); + settings.put( AvailableSettings.PREFER_NATIVE_ENUM_TYPES, "false" ); } @Test diff --git a/hibernate-envers/src/test/java/org/hibernate/orm/test/envers/integration/collection/EnumSet.java b/hibernate-envers/src/test/java/org/hibernate/orm/test/envers/integration/collection/EnumSet.java index 41cad7a420..2489005425 100644 --- a/hibernate-envers/src/test/java/org/hibernate/orm/test/envers/integration/collection/EnumSet.java +++ b/hibernate-envers/src/test/java/org/hibernate/orm/test/envers/integration/collection/EnumSet.java @@ -9,9 +9,12 @@ package org.hibernate.orm.test.envers.integration.collection; import java.sql.Types; import java.util.Arrays; import java.util.List; +import java.util.Map; + import jakarta.persistence.EntityManager; import org.assertj.core.api.Assertions; +import org.hibernate.cfg.AvailableSettings; import org.hibernate.engine.spi.SessionImplementor; import org.hibernate.metamodel.mapping.CompositeIdentifierMapping; import org.hibernate.metamodel.mapping.EntityMappingType; @@ -42,6 +45,12 @@ public class EnumSet extends BaseEnversJPAFunctionalTestCase { return new Class[] {EnumSetEntity.class}; } + @Override + protected void addConfigOptions(Map options) { + super.addConfigOptions( options ); + options.put( AvailableSettings.PREFER_NATIVE_ENUM_TYPES, "false" ); + } + @Test @Priority(10) public void initData() { diff --git a/hibernate-envers/src/test/java/org/hibernate/orm/test/envers/integration/customtype/EnumTypeTest.java b/hibernate-envers/src/test/java/org/hibernate/orm/test/envers/integration/customtype/EnumTypeTest.java index 74b5a072c9..b022b0edf4 100644 --- a/hibernate-envers/src/test/java/org/hibernate/orm/test/envers/integration/customtype/EnumTypeTest.java +++ b/hibernate-envers/src/test/java/org/hibernate/orm/test/envers/integration/customtype/EnumTypeTest.java @@ -6,6 +6,9 @@ */ package org.hibernate.orm.test.envers.integration.customtype; +import java.util.Map; + +import org.hibernate.cfg.AvailableSettings; import org.hibernate.orm.test.envers.BaseEnversJPAFunctionalTestCase; import org.hibernate.orm.test.envers.Priority; import org.hibernate.orm.test.envers.entities.customtype.EnumTypeEntity; @@ -26,6 +29,12 @@ public class EnumTypeTest extends BaseEnversJPAFunctionalTestCase { return new Class[] {EnumTypeEntity.class}; } + @Override + protected void addConfigOptions(Map options) { + super.addConfigOptions( options ); + options.put( AvailableSettings.PREFER_NATIVE_ENUM_TYPES, "false" ); + } + @Test @Priority(10) public void initData() { diff --git a/tooling/metamodel-generator/src/main/java/org/hibernate/processor/validation/MockSessionFactory.java b/tooling/metamodel-generator/src/main/java/org/hibernate/processor/validation/MockSessionFactory.java index ab566c19bd..7ee4d912b6 100644 --- a/tooling/metamodel-generator/src/main/java/org/hibernate/processor/validation/MockSessionFactory.java +++ b/tooling/metamodel-generator/src/main/java/org/hibernate/processor/validation/MockSessionFactory.java @@ -405,6 +405,11 @@ public abstract class MockSessionFactory return MetadataBuildingContext.super.isPreferJavaTimeJdbcTypesEnabled(); } + @Override + public boolean isPreferNativeEnumTypesEnabled() { + return MetadataBuildingContext.super.isPreferNativeEnumTypesEnabled(); + } + @Override public FastSessionServices getFastSessionServices() { throw new UnsupportedOperationException("operation not supported");