From febf39cc553d9bdaded3a53c42747937888f4881 Mon Sep 17 00:00:00 2001 From: Gavin Date: Thu, 27 Apr 2023 16:36:37 +0200 Subject: [PATCH] HHH-16125 complete redesign of how enum mappings work - introduce SqlTypes.ENUM - no more converters! - finish of Potgres enum support - disable BIND for enums in Criteria on PostgreSQL (PostgreSQL doesn't do the needed type conversion to the enum type) --- .../internal/EnumeratedValueResolution.java | 188 -------------- .../internal/InferredBasicValueResolver.java | 231 +++--------------- .../boot/spi/InFlightMetadataCollector.java | 3 +- .../java/org/hibernate/dialect/Dialect.java | 11 +- .../org/hibernate/dialect/MySQLDialect.java | 10 + .../hibernate/dialect/MySQLEnumJdbcType.java | 82 +++++++ .../dialect/OracleBooleanJdbcType.java | 3 +- .../hibernate/dialect/OracleJsonJdbcType.java | 3 +- .../hibernate/dialect/PostgreSQLDialect.java | 10 + .../dialect/PostgreSQLEnumJdbcType.java | 116 +++++++++ .../org/hibernate/mapping/BasicValue.java | 26 +- .../java/org/hibernate/mapping/Column.java | 24 +- .../sqm/internal/SqmCriteriaNodeBuilder.java | 38 +-- .../function/ArgumentTypesValidator.java | 3 +- .../sqm/sql/BaseSqmToSqlAstConverter.java | 64 ++--- .../sql/ast/tree/expression/QueryLiteral.java | 23 +- .../java/org/hibernate/type/BasicType.java | 9 + .../java/org/hibernate/type/SqlTypes.java | 7 + .../converter/internal/EnumHelper.java | 2 +- .../internal/NamedEnumValueConverter.java | 33 +-- .../internal/NativeEnumValueConverter.java | 97 -------- .../internal/OrdinalEnumValueConverter.java | 10 +- .../converter/spi/BasicValueConverter.java | 7 - .../type/descriptor/java/EnumJavaType.java | 27 +- .../type/descriptor/java/JavaType.java | 15 ++ .../type/descriptor/jdbc/IntegerJdbcType.java | 1 - .../type/descriptor/jdbc/JdbcType.java | 13 +- .../descriptor/jdbc/NativeEnumJdbcType.java | 55 ----- .../jdbc/OracleJsonBlobJdbcType.java | 3 +- .../jdbc/internal/JdbcTypeBaseline.java | 3 + .../type/descriptor/sql/DdlType.java | 18 +- .../descriptor/sql/internal/DdlTypeImpl.java | 5 - .../internal/NamedNativeEnumDdlTypeImpl.java | 57 +++++ .../sql/internal/NativeEnumDdlTypeImpl.java | 57 +++++ .../descriptor/sql/spi/DdlTypeRegistry.java | 22 +- .../metadata/BasicMetadataGenerator.java | 2 - 36 files changed, 585 insertions(+), 693 deletions(-) delete mode 100644 hibernate-core/src/main/java/org/hibernate/boot/model/process/internal/EnumeratedValueResolution.java create mode 100644 hibernate-core/src/main/java/org/hibernate/dialect/MySQLEnumJdbcType.java create mode 100644 hibernate-core/src/main/java/org/hibernate/dialect/PostgreSQLEnumJdbcType.java delete mode 100644 hibernate-core/src/main/java/org/hibernate/type/descriptor/converter/internal/NativeEnumValueConverter.java delete mode 100644 hibernate-core/src/main/java/org/hibernate/type/descriptor/jdbc/NativeEnumJdbcType.java create mode 100644 hibernate-core/src/main/java/org/hibernate/type/descriptor/sql/internal/NamedNativeEnumDdlTypeImpl.java create mode 100644 hibernate-core/src/main/java/org/hibernate/type/descriptor/sql/internal/NativeEnumDdlTypeImpl.java diff --git a/hibernate-core/src/main/java/org/hibernate/boot/model/process/internal/EnumeratedValueResolution.java b/hibernate-core/src/main/java/org/hibernate/boot/model/process/internal/EnumeratedValueResolution.java deleted file mode 100644 index fdc517ac5f..0000000000 --- a/hibernate-core/src/main/java/org/hibernate/boot/model/process/internal/EnumeratedValueResolution.java +++ /dev/null @@ -1,188 +0,0 @@ -/* - * 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.hibernate.boot.model.process.internal; - -import java.util.Locale; - -import org.hibernate.boot.registry.classloading.spi.ClassLoaderService; -import org.hibernate.boot.spi.BootstrapContext; -import org.hibernate.boot.spi.MetadataBuildingContext; -import org.hibernate.internal.util.StringHelper; -import org.hibernate.mapping.BasicValue; -import org.hibernate.service.ServiceRegistry; -import org.hibernate.type.ConvertedBasicType; -import org.hibernate.type.descriptor.WrapperOptions; -import org.hibernate.type.descriptor.converter.internal.NamedEnumValueConverter; -import org.hibernate.type.descriptor.converter.internal.NativeEnumValueConverter; -import org.hibernate.type.descriptor.converter.internal.OrdinalEnumValueConverter; -import org.hibernate.type.descriptor.converter.spi.EnumValueConverter; -import org.hibernate.type.descriptor.java.EnumJavaType; -import org.hibernate.type.descriptor.java.ImmutableMutabilityPlan; -import org.hibernate.type.descriptor.java.JavaType; -import org.hibernate.type.descriptor.java.MutabilityPlan; -import org.hibernate.type.descriptor.java.ObjectJavaType; -import org.hibernate.type.descriptor.java.spi.JavaTypeRegistry; -import org.hibernate.type.descriptor.jdbc.JdbcType; -import org.hibernate.type.descriptor.jdbc.JdbcTypeIndicators; -import org.hibernate.type.descriptor.jdbc.NativeEnumJdbcType; -import org.hibernate.type.descriptor.jdbc.spi.JdbcTypeRegistry; -import org.hibernate.type.internal.ConvertedBasicTypeImpl; -import org.hibernate.type.spi.TypeConfiguration; - -import jakarta.persistence.EnumType; - -import static org.hibernate.type.SqlTypes.CHAR; -import static org.hibernate.type.SqlTypes.VARCHAR; -import static org.hibernate.type.SqlTypes.isCharacterType; - -/** - * Resolution for {@linkplain Enum enum} mappings using {@link jakarta.persistence.Enumerated}, - * either implicitly or explicitly - * - * @author Steve Ebersole - */ -public class EnumeratedValueResolution,R> implements BasicValue.Resolution { - public static final String PREFIX = "enum::"; - - private final EnumValueConverter valueConverter; - private final ConvertedBasicType jdbcMapping; - - public EnumeratedValueResolution( - JdbcType jdbcType, - EnumValueConverter valueConverter) { - this.valueConverter = valueConverter; - - final String externalizableName = createName( valueConverter ); - this.jdbcMapping = new ConvertedBasicTypeImpl<>( externalizableName, jdbcType, valueConverter ); - - // todo (enum) : register database objects if needed - } - - private String createName(EnumValueConverter valueConverter) { - return String.format( - Locale.ROOT, - PREFIX + "%s::%s", - valueConverter.getDomainJavaType().getJavaType().getName(), - enumStyle( valueConverter ).name() - ); - } - - private static EnumType enumStyle(EnumValueConverter valueConverter) { - if ( valueConverter instanceof NamedEnumValueConverter - || valueConverter instanceof NativeEnumValueConverter ) { - return EnumType.STRING; - } - else if ( valueConverter instanceof OrdinalEnumValueConverter ) { - return EnumType.ORDINAL; - } - throw new UnsupportedOperationException(); - } - - @Override - public ConvertedBasicType getJdbcMapping() { - return jdbcMapping; - } - - @Override - public ConvertedBasicType getLegacyResolvedBasicType() { - return jdbcMapping; - } - - @Override - public JavaType getDomainJavaType() { - return jdbcMapping.getJavaTypeDescriptor(); - } - - @Override - public JavaType getRelationalJavaType() { - return jdbcMapping.getJdbcJavaType(); - } - - @Override - public JdbcType getJdbcType() { - return jdbcMapping.getJdbcType(); - } - - @Override - public EnumValueConverter getValueConverter() { - return valueConverter; - } - - @Override - public MutabilityPlan getMutabilityPlan() { - return ImmutableMutabilityPlan.instance(); - } - - public static > EnumeratedValueResolution fromName( - String name, - JdbcTypeIndicators jdbcTypeIndicators, - MetadataBuildingContext context) { - assert name != null; - assert name.startsWith( PREFIX ); - - final String[] parts = StringHelper.split( "::", name ); - assert parts.length == 3; - assert "enum".equals( parts[0] ); - - final TypeConfiguration typeConfiguration = context.getBootstrapContext().getTypeConfiguration(); - final JavaTypeRegistry javaTypeRegistry = typeConfiguration.getJavaTypeRegistry(); - final JdbcTypeRegistry jdbcTypeRegistry = typeConfiguration.getJdbcTypeRegistry(); - - final Class enumClass = resolveEnumClass( parts[1], context.getBootstrapContext() ); - final jakarta.persistence.EnumType style = jakarta.persistence.EnumType.valueOf( parts[ 2 ] ); - - @SuppressWarnings({"unchecked", "rawtypes"}) - final EnumJavaType enumJavaType = (EnumJavaType) javaTypeRegistry.getDescriptor( enumClass ); - final JdbcType jdbcType = enumJavaType.getRecommendedJdbcType( jdbcTypeIndicators ); - final EnumValueConverter converter; - - switch ( style ) { - case ORDINAL: - final JavaType integerJavaType = jdbcType.getJdbcRecommendedJavaTypeMapping( - jdbcTypeIndicators.getColumnPrecision(), - jdbcTypeIndicators.getColumnScale(), - typeConfiguration - ); - converter = new OrdinalEnumValueConverter<>( enumJavaType, jdbcType, integerJavaType ); - break; - case STRING: - if (jdbcType instanceof NativeEnumJdbcType) { - converter = new NativeEnumValueConverter<>( enumJavaType, jdbcType, new ObjectJavaType() { - @Override - public X unwrap(Object value, Class type, WrapperOptions options) { - if ( String.class.equals(type) && value instanceof Enum) { - return (X) ((Enum) value).name(); - } - else { - return super.unwrap(value, type, options); - } - } - } ); - } - else { - final JavaType stringJavaType = jdbcType.getJdbcRecommendedJavaTypeMapping( - jdbcTypeIndicators.getColumnPrecision(), - jdbcTypeIndicators.getColumnScale(), - typeConfiguration - ); - converter = new NamedEnumValueConverter<>( enumJavaType, jdbcType, stringJavaType ); - } - break; - default: - throw new IllegalArgumentException( ); - } - - return new EnumeratedValueResolution<>( jdbcType, converter ); - } - - private static > Class resolveEnumClass(String enumClassName, BootstrapContext bootstrapContext) { - final ServiceRegistry serviceRegistry = bootstrapContext.getServiceRegistry(); - final ClassLoaderService classLoaderService = serviceRegistry.getService( ClassLoaderService.class ); - - return classLoaderService.classForName( enumClassName ); - } -} diff --git a/hibernate-core/src/main/java/org/hibernate/boot/model/process/internal/InferredBasicValueResolver.java b/hibernate-core/src/main/java/org/hibernate/boot/model/process/internal/InferredBasicValueResolver.java index fe6e26a9b6..c123cf1a13 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/model/process/internal/InferredBasicValueResolver.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/model/process/internal/InferredBasicValueResolver.java @@ -12,6 +12,7 @@ import java.util.function.Function; import java.util.function.Supplier; import org.hibernate.MappingException; +import org.hibernate.boot.spi.BootstrapContext; import org.hibernate.boot.spi.MetadataBuildingContext; import org.hibernate.dialect.Dialect; import org.hibernate.mapping.BasicValue; @@ -23,32 +24,23 @@ import org.hibernate.type.AdjustableBasicType; import org.hibernate.type.BasicPluralType; import org.hibernate.type.BasicType; import org.hibernate.type.SerializableType; -import org.hibernate.type.descriptor.WrapperOptions; -import org.hibernate.type.descriptor.converter.internal.NamedEnumValueConverter; -import org.hibernate.type.descriptor.converter.internal.NativeEnumValueConverter; -import org.hibernate.type.descriptor.converter.internal.OrdinalEnumValueConverter; -import org.hibernate.type.descriptor.converter.spi.EnumValueConverter; import org.hibernate.type.descriptor.java.BasicJavaType; import org.hibernate.type.descriptor.java.BasicPluralJavaType; import org.hibernate.type.descriptor.java.EnumJavaType; +import org.hibernate.type.descriptor.java.ImmutableMutabilityPlan; import org.hibernate.type.descriptor.java.JavaType; -import org.hibernate.type.descriptor.java.JavaTypeHelper; import org.hibernate.type.descriptor.java.MutabilityPlan; -import org.hibernate.type.descriptor.java.ObjectJavaType; import org.hibernate.type.descriptor.java.SerializableJavaType; import org.hibernate.type.descriptor.java.TemporalJavaType; import org.hibernate.type.descriptor.jdbc.JdbcType; import org.hibernate.type.descriptor.jdbc.JdbcTypeIndicators; -import org.hibernate.type.descriptor.jdbc.NativeEnumJdbcType; import org.hibernate.type.descriptor.jdbc.ObjectJdbcType; +import org.hibernate.type.internal.BasicTypeImpl; import org.hibernate.type.spi.TypeConfiguration; -import jakarta.persistence.EnumType; import jakarta.persistence.TemporalType; -import static org.hibernate.type.SqlTypes.SMALLINT; -import static org.hibernate.type.SqlTypes.TINYINT; -import static org.hibernate.type.SqlTypes.isCharacterType; +import static org.hibernate.type.descriptor.java.JavaTypeHelper.isTemporal; /** * BasicValue.Resolution resolver for cases where no explicit @@ -69,7 +61,8 @@ public class InferredBasicValueResolver { String propertyName, MetadataBuildingContext buildingContext) { final Dialect dialect = buildingContext.getMetadataCollector().getDatabase().getDialect(); - final TypeConfiguration typeConfiguration = buildingContext.getBootstrapContext().getTypeConfiguration(); + final BootstrapContext bootstrapContext = buildingContext.getBootstrapContext(); + final TypeConfiguration typeConfiguration = bootstrapContext.getTypeConfiguration(); final JavaType reflectedJtd = reflectedJtdResolver.get(); @@ -79,31 +72,19 @@ public class InferredBasicValueResolver { final BasicType jdbcMapping; - if ( explicitJavaType != null ) { + if (explicitJavaType != null) { // we have an explicit JavaType - if ( explicitJavaType instanceof EnumJavaType ) { - return fromEnum( - (EnumJavaType) explicitJavaType, - null, - explicitJdbcType, - stdIndicators, - buildingContext - ); - } - else if ( JavaTypeHelper.isTemporal( explicitJavaType ) ) { + if ( isTemporal( explicitJavaType ) ) { return fromTemporal( (TemporalJavaType) explicitJavaType, null, explicitJdbcType, - resolvedJavaType, explicitMutabilityPlanAccess, - stdIndicators, - typeConfiguration + stdIndicators ); } else if ( explicitJdbcType != null ) { // we also have an explicit JdbcType - jdbcMapping = typeConfiguration.getBasicTypeRegistry().resolve( explicitJavaType, explicitJdbcType @@ -132,30 +113,25 @@ public class InferredBasicValueResolver { else if ( reflectedJtd != null ) { // we were able to determine the "reflected java-type" // Use JTD if we know it to apply any specialized resolutions - if ( reflectedJtd instanceof EnumJavaType ) { return fromEnum( (EnumJavaType) reflectedJtd, - null, explicitJdbcType, stdIndicators, - buildingContext + bootstrapContext ); } - else if ( JavaTypeHelper.isTemporal( reflectedJtd ) ) { + else if ( isTemporal( reflectedJtd ) ) { return fromTemporal( (TemporalJavaType) reflectedJtd, null, explicitJdbcType, - resolvedJavaType, explicitMutabilityPlanAccess, - stdIndicators, - typeConfiguration + stdIndicators ); } else if ( explicitJdbcType != null ) { // we also have an explicit JdbcType - jdbcMapping = typeConfiguration.getBasicTypeRegistry().resolve( reflectedJtd, explicitJdbcType @@ -170,24 +146,20 @@ public class InferredBasicValueResolver { final JavaType elementJtd = containerJtd.getElementJavaType(); final BasicType registeredElementType; if ( elementJtd instanceof EnumJavaType ) { - final EnumeratedValueResolution resolution = fromEnum( + final BasicValue.Resolution resolution = fromEnum( (EnumJavaType) elementJtd, - null, - null, + explicitJdbcType, stdIndicators, - buildingContext - ); - registeredElementType = resolution.getJdbcMapping(); + bootstrapContext); + registeredElementType = (BasicType) resolution.getJdbcMapping(); } - else if ( JavaTypeHelper.isTemporal( elementJtd ) ) { - final InferredBasicValueResolution resolution = InferredBasicValueResolver.fromTemporal( - (TemporalJavaType) elementJtd, + else if ( isTemporal( elementJtd ) ) { + final BasicValue.Resolution resolution = fromTemporal( + (TemporalJavaType) elementJtd, null, null, - resolvedJavaType, explicitMutabilityPlanAccess, - stdIndicators, - typeConfiguration + stdIndicators ); registeredElementType = resolution.getLegacyResolvedBasicType(); } @@ -330,163 +302,40 @@ public class InferredBasicValueResolver { } } - public static , R> EnumeratedValueResolution fromEnum( + public static > BasicValue.Resolution fromEnum( EnumJavaType enumJavaType, - BasicJavaType explicitJavaType, JdbcType explicitJdbcType, JdbcTypeIndicators stdIndicators, - MetadataBuildingContext context) { - final EnumType enumStyle = stdIndicators.getEnumeratedType(); - if ( enumStyle == null ) { - // NOTE : separate from the explicit ORDINAL check to facilitate - // handling native database enum types. In theory anyway - atm - // we cannot discern an implicit (default value) or explicit style - // due to HCANN and annotation handling for default values - - //noinspection unchecked - return (EnumeratedValueResolution) ordinalEnumValueResolution( - enumJavaType, - (BasicJavaType)explicitJavaType, - explicitJdbcType, - context - ); - } - switch ( enumStyle ) { - case STRING: - //noinspection unchecked - return (EnumeratedValueResolution) stringEnumValueResolution( - enumJavaType, - explicitJavaType, - explicitJdbcType, - stdIndicators, - context - ); - case ORDINAL: - //noinspection unchecked - return (EnumeratedValueResolution) ordinalEnumValueResolution( - enumJavaType, - (BasicJavaType)explicitJavaType, - explicitJdbcType, - context - ); - default: - throw new MappingException( "Unknown enumeration-style (JPA EnumType) : " + enumStyle ); - } - } - - private static , N extends Number> EnumeratedValueResolution ordinalEnumValueResolution( - EnumJavaType enumJavaType, - BasicJavaType explicitJavaType, - JdbcType explicitJdbcType, - MetadataBuildingContext context) { - final JdbcType jdbcType = ordinalJdbcType( explicitJdbcType, enumJavaType, context ); - final JavaType relationalJavaType = ordinalJavaType( explicitJavaType, jdbcType, context ); - return new EnumeratedValueResolution<>( - jdbcType, - new OrdinalEnumValueConverter<>( enumJavaType, jdbcType, relationalJavaType ) - ); - } - - private static JdbcType ordinalJdbcType( - JdbcType explicitJdbcType, - EnumJavaType enumJavaType, - MetadataBuildingContext context) { - return explicitJdbcType != null - ? explicitJdbcType - : context.getMetadataCollector().getTypeConfiguration().getJdbcTypeRegistry().getDescriptor( enumJavaType.hasManyValues() ? SMALLINT : TINYINT ); - } - - private static JavaType ordinalJavaType( - JavaType explicitJavaType, - JdbcType jdbcType, - MetadataBuildingContext context) { - if ( explicitJavaType != null ) { - if ( !Integer.class.isAssignableFrom( explicitJavaType.getJavaTypeClass() ) ) { - throw new MappingException( - "Explicit JavaType [" + explicitJavaType + - "] applied to enumerated value with EnumType#ORDINAL" + - " should handle `java.lang.Integer` as its relational type descriptor" - ); - } - return explicitJavaType; - } - else { - return jdbcType.getJdbcRecommendedJavaTypeMapping( - null, - null, - context.getMetadataCollector().getTypeConfiguration() - ); - } - } - - private static > EnumeratedValueResolution stringEnumValueResolution( - EnumJavaType enumJavaType, - BasicJavaType explicitJavaType, - JdbcType explicitJdbcType, - JdbcTypeIndicators stdIndicators, - MetadataBuildingContext context) { + BootstrapContext bootstrapContext) { final JdbcType jdbcType = explicitJdbcType == null ? enumJavaType.getRecommendedJdbcType( stdIndicators ) : explicitJdbcType; - final EnumValueConverter converter; - if ( jdbcType instanceof NativeEnumJdbcType ) { - converter = new NativeEnumValueConverter<>( enumJavaType, jdbcType, new ObjectJavaType() { - @Override - public X unwrap(Object value, Class type, WrapperOptions options) { - if ( String.class.equals(type) && value instanceof Enum) { - return (X) ((Enum) value).name(); - } - else { - return super.unwrap(value, type, options); - } - } - } ); - } - else { - converter = new NamedEnumValueConverter<>( - enumJavaType, - jdbcType, - stringJavaType( explicitJavaType, stdIndicators, context ) - ); - } - return new EnumeratedValueResolution<>( jdbcType, converter ); + final BasicTypeImpl basicType = new BasicTypeImpl<>( enumJavaType, jdbcType ); + bootstrapContext.registerAdHocBasicType( basicType ); + return new InferredBasicValueResolution<>( + basicType, + enumJavaType, + enumJavaType, + jdbcType, + basicType, + ImmutableMutabilityPlan.instance() + ); } - private static JavaType stringJavaType( - BasicJavaType explicitJavaType, - JdbcTypeIndicators stdIndicators, - MetadataBuildingContext context) { - if ( explicitJavaType != null ) { - if ( ! String.class.isAssignableFrom( explicitJavaType.getJavaTypeClass() ) ) { - throw new MappingException( - "Explicit JavaType [" + explicitJavaType + - "] applied to enumerated value with EnumType#STRING" + - " should handle `java.lang.String` as its relational type descriptor" - ); - } - return (JavaType) explicitJavaType; - } - else { - return context.getMetadataCollector().getTypeConfiguration().getJavaTypeRegistry() - .getDescriptor( stdIndicators.getColumnLength() == 1 ? Character.class : String.class ); - } - } - - public static InferredBasicValueResolution fromTemporal( + public static BasicValue.Resolution fromTemporal( TemporalJavaType reflectedJtd, BasicJavaType explicitJavaType, JdbcType explicitJdbcType, - Type resolvedJavaType, Function explicitMutabilityPlanAccess, - JdbcTypeIndicators stdIndicators, - TypeConfiguration typeConfiguration) { + JdbcTypeIndicators stdIndicators) { + final TypeConfiguration typeConfiguration = stdIndicators.getTypeConfiguration(); final TemporalType requestedTemporalPrecision = stdIndicators.getTemporalPrecision(); // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Case #1 - explicit JavaType if ( explicitJavaType != null ) { - if ( !JavaTypeHelper.isTemporal( explicitJavaType ) ) { + if ( !isTemporal( explicitJavaType ) ) { throw new MappingException( "Explicit JavaType [" + explicitJavaType + "] defined for temporal value must implement TemporalJavaType" @@ -495,7 +344,6 @@ public class InferredBasicValueResolver { @SuppressWarnings("unchecked") final TemporalJavaType explicitTemporalJtd = (TemporalJavaType) explicitJavaType; - if ( requestedTemporalPrecision != null && explicitTemporalJtd.getPrecision() != requestedTemporalPrecision ) { throw new MappingException( "Temporal precision (`jakarta.persistence.TemporalType`) mismatch... requested precision = " + requestedTemporalPrecision + @@ -507,9 +355,7 @@ public class InferredBasicValueResolver { final JdbcType jdbcType = explicitJdbcType != null ? explicitJdbcType : explicitTemporalJtd.getRecommendedJdbcType( stdIndicators ); - final BasicType jdbcMapping = typeConfiguration.getBasicTypeRegistry().resolve( explicitTemporalJtd, jdbcType ); - final MutabilityPlan mutabilityPlan = determineMutabilityPlan( explicitMutabilityPlanAccess, explicitTemporalJtd, typeConfiguration ); return new InferredBasicValueResolution<>( jdbcMapping, @@ -531,10 +377,7 @@ public class InferredBasicValueResolver { final TemporalJavaType jtd; if ( requestedTemporalPrecision != null ) { - jtd = reflectedJtd.resolveTypeForPrecision( - requestedTemporalPrecision, - typeConfiguration - ); + jtd = reflectedJtd.resolveTypeForPrecision( requestedTemporalPrecision, typeConfiguration ); } else { jtd = reflectedJtd; diff --git a/hibernate-core/src/main/java/org/hibernate/boot/spi/InFlightMetadataCollector.java b/hibernate-core/src/main/java/org/hibernate/boot/spi/InFlightMetadataCollector.java index 4fad02a2d5..70cfea48c1 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/spi/InFlightMetadataCollector.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/spi/InFlightMetadataCollector.java @@ -38,7 +38,6 @@ import org.hibernate.boot.query.NamedNativeQueryDefinition; import org.hibernate.boot.query.NamedProcedureCallDefinition; import org.hibernate.boot.query.NamedResultSetMappingDescriptor; import org.hibernate.engine.spi.FilterDefinition; -import org.hibernate.engine.spi.Mapping; import org.hibernate.mapping.Collection; import org.hibernate.mapping.Column; import org.hibernate.mapping.Component; @@ -64,7 +63,7 @@ import jakarta.persistence.AttributeConverter; * * @since 5.0 */ -public interface InFlightMetadataCollector extends Mapping, MetadataImplementor { +public interface InFlightMetadataCollector extends MetadataImplementor { BootstrapContext getBootstrapContext(); /** diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/Dialect.java b/hibernate-core/src/main/java/org/hibernate/dialect/Dialect.java index 30c5432502..93b153f835 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/Dialect.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/Dialect.java @@ -204,6 +204,7 @@ import static org.hibernate.cfg.AvailableSettings.NON_CONTEXTUAL_LOB_CREATION; import static org.hibernate.cfg.AvailableSettings.STATEMENT_BATCH_SIZE; import static org.hibernate.cfg.AvailableSettings.USE_GET_GENERATED_KEYS; import static org.hibernate.internal.util.StringHelper.parseCommaSeparatedString; +import static org.hibernate.internal.util.collections.ArrayHelper.EMPTY_STRING_ARRAY; import static org.hibernate.type.SqlTypes.ARRAY; import static org.hibernate.type.SqlTypes.BIGINT; import static org.hibernate.type.SqlTypes.BINARY; @@ -762,7 +763,7 @@ public abstract class Dialect implements ConversionContext, TypeContributor, Fun } public String[] getCreateEnumTypeCommand(String name, String[] values) { - return null; + return EMPTY_STRING_ARRAY; } public String[] getCreateEnumTypeCommand(Class> enumType) { @@ -771,6 +772,14 @@ public abstract class Dialect implements ConversionContext, TypeContributor, Fun return getCreateEnumTypeCommand( enumType.getSimpleName(), values ); } + public String[] getDropEnumTypeCommand(String name) { + return EMPTY_STRING_ARRAY; + } + + public String[] getDropEnumTypeCommand(Class> enumType) { + return getDropEnumTypeCommand( enumType.getSimpleName() ); + } + /** * Render a SQL check condition for a column that represents an enumerated value * by its {@linkplain jakarta.persistence.EnumType#STRING string representation}. 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 cbf382e60c..e0adfd3ada 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/MySQLDialect.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/MySQLDialect.java @@ -76,6 +76,7 @@ import org.hibernate.type.descriptor.jdbc.NullJdbcType; import org.hibernate.type.descriptor.jdbc.spi.JdbcTypeRegistry; import org.hibernate.type.descriptor.sql.internal.CapacityDependentDdlType; import org.hibernate.type.descriptor.sql.internal.DdlTypeImpl; +import org.hibernate.type.descriptor.sql.internal.NativeEnumDdlTypeImpl; import org.hibernate.type.descriptor.sql.spi.DdlTypeRegistry; import jakarta.persistence.TemporalType; @@ -378,6 +379,8 @@ public class MySQLDialect extends Dialect { .withTypeCapacity( maxLobLen, "text" ) .build() ); + + ddlTypeRegistry.addDescriptor( new NativeEnumDdlTypeImpl(this) ); } @Deprecated @@ -641,6 +644,8 @@ public class MySQLDialect extends Dialect { .getDescriptor( Object.class ) ) ); + + jdbcTypeRegistry.addDescriptor( new MySQLEnumJdbcType() ); } @Override @@ -869,6 +874,11 @@ public class MySQLDialect extends Dialect { return getMySQLVersion().isSameOrAfter( 8, 0, 16 ); } + @Override + public boolean hasNativeEnums() { + return true; + } + @Override public String getEnumTypeDeclaration(String name, String[] values) { StringBuilder type = new StringBuilder(); diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/MySQLEnumJdbcType.java b/hibernate-core/src/main/java/org/hibernate/dialect/MySQLEnumJdbcType.java new file mode 100644 index 0000000000..f7eb71fb6b --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/dialect/MySQLEnumJdbcType.java @@ -0,0 +1,82 @@ +/* + * 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.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; + +/** + * @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 ); + } + + @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/OracleBooleanJdbcType.java b/hibernate-core/src/main/java/org/hibernate/dialect/OracleBooleanJdbcType.java index 947c7cf6f9..0e2621158c 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/OracleBooleanJdbcType.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/OracleBooleanJdbcType.java @@ -6,6 +6,7 @@ */ package org.hibernate.dialect; +import org.hibernate.type.descriptor.converter.spi.BasicValueConverter; import org.hibernate.type.descriptor.java.JavaType; import org.hibernate.type.descriptor.jdbc.BooleanJdbcType; @@ -14,7 +15,7 @@ public class OracleBooleanJdbcType extends BooleanJdbcType { public static final OracleBooleanJdbcType INSTANCE = new OracleBooleanJdbcType(); @Override - public String getCheckCondition(String columnName, JavaType javaType, Dialect dialect) { + public String getCheckCondition(String columnName, JavaType javaType, BasicValueConverter converter, Dialect dialect) { return columnName + " in (0,1)"; } } diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/OracleJsonJdbcType.java b/hibernate-core/src/main/java/org/hibernate/dialect/OracleJsonJdbcType.java index 1f3edc9abb..c5a040163c 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/OracleJsonJdbcType.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/OracleJsonJdbcType.java @@ -8,6 +8,7 @@ package org.hibernate.dialect; import org.hibernate.metamodel.mapping.EmbeddableMappingType; import org.hibernate.metamodel.spi.RuntimeModelCreationContext; +import org.hibernate.type.descriptor.converter.spi.BasicValueConverter; import org.hibernate.type.descriptor.java.JavaType; import org.hibernate.type.descriptor.jdbc.AggregateJdbcType; import org.hibernate.type.descriptor.jdbc.OracleJsonBlobJdbcType; @@ -41,7 +42,7 @@ public class OracleJsonJdbcType extends OracleJsonBlobJdbcType { } @Override - public String getCheckCondition(String columnName, JavaType javaType, Dialect dialect) { + public String getCheckCondition(String columnName, JavaType javaType, BasicValueConverter converter, Dialect dialect) { // No check constraint necessary, because the JSON DDL type is already OSON encoded return null; } diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/PostgreSQLDialect.java b/hibernate-core/src/main/java/org/hibernate/dialect/PostgreSQLDialect.java index 8e0c2dc8d7..6baa5bf54d 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/PostgreSQLDialect.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/PostgreSQLDialect.java @@ -87,6 +87,7 @@ import org.hibernate.type.descriptor.jdbc.XmlJdbcType; import org.hibernate.type.descriptor.jdbc.spi.JdbcTypeRegistry; import org.hibernate.type.descriptor.sql.internal.CapacityDependentDdlType; import org.hibernate.type.descriptor.sql.internal.DdlTypeImpl; +import org.hibernate.type.descriptor.sql.internal.NamedNativeEnumDdlTypeImpl; import org.hibernate.type.descriptor.sql.internal.Scale6IntervalSecondDdlType; import org.hibernate.type.descriptor.sql.spi.DdlTypeRegistry; import org.hibernate.type.spi.TypeConfiguration; @@ -271,6 +272,8 @@ public class PostgreSQLDialect extends Dialect { // Prefer jsonb if possible ddlTypeRegistry.addDescriptor( new DdlTypeImpl( JSON, "jsonb", this ) ); + + ddlTypeRegistry.addDescriptor( new NamedNativeEnumDdlTypeImpl( this ) ); } @Override @@ -421,6 +424,11 @@ public class PostgreSQLDialect extends Dialect { return new String[] { type.toString(), cast1.toString(), cast2.toString() }; } + @Override + public String[] getDropEnumTypeCommand(String name) { + return new String[] { "drop type if exists " + name + " cascade" }; + } + @Override public String currentTime() { return "localtime"; @@ -1408,6 +1416,8 @@ public class PostgreSQLDialect extends Dialect { .getDescriptor( Object.class ) ) ); + + jdbcTypeRegistry.addDescriptor( new PostgreSQLEnumJdbcType() ); } @Override diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/PostgreSQLEnumJdbcType.java b/hibernate-core/src/main/java/org/hibernate/dialect/PostgreSQLEnumJdbcType.java new file mode 100644 index 0000000000..cce78c73c3 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/dialect/PostgreSQLEnumJdbcType.java @@ -0,0 +1,116 @@ +/* + * 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.dialect; + +import org.hibernate.boot.model.relational.Database; +import org.hibernate.boot.model.relational.NamedAuxiliaryDatabaseObject; +import org.hibernate.boot.spi.InFlightMetadataCollector; +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 java.sql.CallableStatement; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Types; + +import static java.util.Collections.emptySet; +import static org.hibernate.type.SqlTypes.ENUM; + +/** + * @author Gavin King + */ +public class PostgreSQLEnumJdbcType implements JdbcType { + + @Override + public int getJdbcTypeCode() { + return ENUM; + } + + @Override + public JdbcLiteralFormatter getJdbcLiteralFormatter(JavaType javaType) { + return (appender, value, dialect, wrapperOptions) -> appender.appendSql( "'" + ((Enum) value).name() + "'::" + + dialect.getEnumTypeDeclaration( (Class>) javaType.getJavaType() ) ); + } + + @Override + public String getFriendlyName() { + return "ENUM"; + } + + @Override + public String toString() { + return "EnumTypeDescriptor"; + } + + @Override + public ValueBinder getBinder(JavaType javaType) { + return new BasicBinder<>( javaType, this ) { + @Override + protected void doBindNull(PreparedStatement st, int index, WrapperOptions options) throws SQLException { + st.setNull( index, Types.OTHER ); + } + + @Override + protected void doBindNull(CallableStatement st, String name, WrapperOptions options) throws SQLException { + st.setNull( name, Types.OTHER ); + } + + @Override + protected void doBind(PreparedStatement st, X value, int index, WrapperOptions options) + throws SQLException { + st.setObject( index, value, Types.OTHER ); + } + + @Override + protected void doBind(CallableStatement st, X value, String name, WrapperOptions options) + throws SQLException { + st.setObject( name, value, Types.OTHER ); + } + }; + } + + @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.getObject( paramIndex ), options ); + } + + @Override + protected X doExtract(CallableStatement statement, int index, WrapperOptions options) throws SQLException { + return getJavaType().wrap( statement.getObject( index ), options ); + } + + @Override + protected X doExtract(CallableStatement statement, String name, WrapperOptions options) throws SQLException { + return getJavaType().wrap( statement.getObject( name ), options ); + } + }; + } + + @Override + public void addAuxiliaryDatabaseObjects(JavaType javaType, InFlightMetadataCollector metadataCollector) { + Database database = metadataCollector.getDatabase(); + Class> enumClass = (Class>) javaType.getJavaType(); + String name = enumClass.getSimpleName(); + String[] create = database.getDialect().getCreateEnumTypeCommand( enumClass ); + if ( create != null ) { + String[] drop = database.getDialect().getDropEnumTypeCommand( enumClass ); + database.addAuxiliaryDatabaseObject( + new NamedAuxiliaryDatabaseObject( name, database.getDefaultNamespace(), create, drop, emptySet(), true ) + ); + } + } +} 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 b284f53194..74cbf070f3 100644 --- a/hibernate-core/src/main/java/org/hibernate/mapping/BasicValue.java +++ b/hibernate-core/src/main/java/org/hibernate/mapping/BasicValue.java @@ -20,15 +20,12 @@ import org.hibernate.boot.model.TypeDefinition; import org.hibernate.boot.model.convert.internal.ClassBasedConverterDescriptor; import org.hibernate.boot.model.convert.spi.ConverterDescriptor; import org.hibernate.boot.model.convert.spi.JpaAttributeConverterCreationContext; -import org.hibernate.boot.model.process.internal.EnumeratedValueResolution; import org.hibernate.boot.model.process.internal.InferredBasicValueResolution; import org.hibernate.boot.model.process.internal.InferredBasicValueResolver; import org.hibernate.boot.model.process.internal.NamedBasicTypeResolution; import org.hibernate.boot.model.process.internal.NamedConverterResolution; import org.hibernate.boot.model.process.internal.UserTypeResolution; import org.hibernate.boot.model.process.internal.VersionResolution; -import org.hibernate.boot.model.relational.AuxiliaryDatabaseObject; -import org.hibernate.boot.model.relational.Database; import org.hibernate.boot.registry.StandardServiceRegistry; import org.hibernate.boot.registry.classloading.spi.ClassLoaderService; import org.hibernate.boot.registry.classloading.spi.ClassLoadingException; @@ -320,18 +317,11 @@ public class BasicValue extends SimpleValue implements JdbcTypeIndicators, Resol resolveColumn( (Column) selectable, getDialect() ); } - Database database = getBuildingContext().getMetadataCollector().getDatabase(); - BasicValueConverter valueConverter = resolution.getValueConverter(); - if ( valueConverter != null ) { - AuxiliaryDatabaseObject udt = valueConverter.getAuxiliaryDatabaseObject( - resolution.getJdbcType(), - database.getDialect(), - database.getDefaultNamespace() - ); - if ( udt != null ) { - database.addAuxiliaryDatabaseObject( udt ); - } - } + resolution.getJdbcType() + .addAuxiliaryDatabaseObjects( + resolution.getRelationalJavaType(), + getBuildingContext().getMetadataCollector() + ); return resolution; } @@ -605,9 +595,9 @@ public class BasicValue extends SimpleValue implements JdbcTypeIndicators, Resol ); } - if ( name.startsWith( EnumeratedValueResolution.PREFIX ) ) { - return EnumeratedValueResolution.fromName( name, stdIndicators, context ); - } +// if ( name.startsWith( EnumeratedValueResolution.PREFIX ) ) { +// return EnumeratedValueResolution.fromName( name, stdIndicators, context ); +// } if ( name.startsWith( BasicTypeImpl.EXTERNALIZED_PREFIX ) ) { final BasicTypeImpl basicType = context.getBootstrapContext().resolveAdHocBasicType( name ); diff --git a/hibernate-core/src/main/java/org/hibernate/mapping/Column.java b/hibernate-core/src/main/java/org/hibernate/mapping/Column.java index dde3b634d3..2f974dd3d7 100644 --- a/hibernate-core/src/main/java/org/hibernate/mapping/Column.java +++ b/hibernate-core/src/main/java/org/hibernate/mapping/Column.java @@ -273,8 +273,9 @@ public class Column implements Selectable, Serializable, Cloneable, ColumnTypeIn try { final Type type = getValue().getType(); sqlTypeName = isArray( type ) + //TODO: remove the special case for array types, this should be handled by the DdlType! ? dialect.getArrayTypeName( getArrayElementTypeName( dialect, ddlTypeRegistry, getArrayElementType( type ) ) ) - : ddlTypeRegistry.getTypeName( getSqlTypeCode( mapping ), getColumnSize( dialect, mapping ) ); + : ddlTypeRegistry.getTypeName( getSqlTypeCode( mapping ), getColumnSize( dialect, mapping ), getUnderlyingType( mapping, type, typeIndex ) ); } catch ( Exception cause ) { throw new MappingException( @@ -291,6 +292,27 @@ public class Column implements Selectable, Serializable, Cloneable, ColumnTypeIn return sqlTypeName; } + private static Type getUnderlyingType(Mapping mapping, Type type, int typeIndex) { + if ( type.isComponentType() ) { + int cols = 0; + for ( Type subtype : ((ComponentType) type).getSubtypes() ) { + int columnSpan = subtype.getColumnSpan( mapping ); + if ( cols+columnSpan > typeIndex ) { + return getUnderlyingType( mapping, subtype, typeIndex-cols ); + } + cols += columnSpan; + } + throw new IndexOutOfBoundsException(); + } + else if ( type.isEntityType() ) { + Type idType = ((EntityType) type).getIdentifierOrUniqueKeyType(mapping); + return getUnderlyingType( mapping, idType, typeIndex ); + } + else { + return type; + } + } + private String getArrayElementTypeName(Dialect dialect, DdlTypeRegistry ddlTypeRegistry, BasicType elementType) { return ddlTypeRegistry.getTypeName( elementType.getJdbcType().getDdlTypeCode(), diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/internal/SqmCriteriaNodeBuilder.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/internal/SqmCriteriaNodeBuilder.java index 39995d76a8..3ae84562e3 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/internal/SqmCriteriaNodeBuilder.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/internal/SqmCriteriaNodeBuilder.java @@ -42,8 +42,8 @@ import org.hibernate.internal.util.collections.CollectionHelper; import org.hibernate.metamodel.model.domain.BasicDomainType; import org.hibernate.metamodel.model.domain.DomainType; import org.hibernate.metamodel.model.domain.JpaMetamodel; -import org.hibernate.metamodel.model.domain.PluralPersistentAttribute; import org.hibernate.metamodel.model.domain.TupleType; +import org.hibernate.metamodel.model.domain.internal.BasicTypeImpl; import org.hibernate.metamodel.model.domain.internal.DiscriminatorSqmPathSource; import org.hibernate.metamodel.model.domain.internal.EmbeddedSqmPathSource; import org.hibernate.metamodel.model.domain.spi.JpaMetamodelImplementor; @@ -150,6 +150,7 @@ import org.hibernate.query.sqm.tree.update.SqmUpdateStatement; import org.hibernate.service.ServiceRegistry; import org.hibernate.type.BasicType; import org.hibernate.type.StandardBasicTypes; +import org.hibernate.type.descriptor.java.EnumJavaType; import org.hibernate.type.descriptor.java.JavaType; import org.hibernate.type.descriptor.java.JavaTypeHelper; import org.hibernate.type.spi.TypeConfiguration; @@ -1122,7 +1123,6 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext, } @Override - @SuppressWarnings("unchecked") public SqmExpression quot(Number x, Expression y) { return createSqmArithmeticNode( BinaryArithmeticOperator.QUOT, @@ -1209,7 +1209,7 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext, return new SqmLiteralNull<>( this ); } - final SqmExpressible expressible = resolveInferredType( value, typeInferenceSource, getTypeConfiguration() ); + SqmExpressible expressible = resolveInferredType( value, typeInferenceSource, getTypeConfiguration() ); if ( expressible.getExpressibleJavaType().isInstance( value ) ) { return new SqmLiteral<>( value, expressible, this ); } @@ -1228,21 +1228,27 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext, } } + @SuppressWarnings({"rawtypes","unchecked"}) private static SqmExpressible resolveInferredType( T value, SqmExpression typeInferenceSource, TypeConfiguration typeConfiguration) { if ( typeInferenceSource != null ) { - //noinspection unchecked return (SqmExpressible) typeInferenceSource.getNodeType(); } - - if ( value == null ) { + else if ( value == null ) { return null; } - - //noinspection unchecked - return (BasicType) typeConfiguration.getBasicTypeForJavaType( value.getClass() ); + else { + Class type = value.getClass(); + BasicType result = typeConfiguration.getBasicTypeForJavaType( type ); + if ( result == null && value instanceof Enum ) { + return new BasicTypeImpl<>( new EnumJavaType<>( type ) ); + } + else { + return result; + } + } } @Override @@ -1770,7 +1776,7 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext, if ( value instanceof SqmExpression ) { return (SqmExpression) value; } - if ( criteriaValueHandlingMode == ValueHandlingMode.INLINE ) { + if ( inlineValue( value ) ) { return literal( value, typeInferenceSource ); } @@ -1846,7 +1852,7 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext, if ( value instanceof SqmExpression ) { return (SqmExpression) value; } - if ( criteriaValueHandlingMode == ValueHandlingMode.INLINE ) { + if ( inlineValue( value ) ) { return literal( value ); } else { @@ -1858,6 +1864,11 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext, } } + private boolean inlineValue(T value) { + return criteriaValueHandlingMode == ValueHandlingMode.INLINE || value instanceof Enum + && queryEngine.getCriteriaBuilder().getSessionFactory().getJdbcServices().getDialect().hasNativeEnums(); + } + @Override public > SqmExpression> values(C collection) { throw new UnsupportedOperationException(); @@ -1905,7 +1916,6 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext, @Override public JpaCoalesce coalesce(Expression x, Y y) { - //noinspection unchecked return coalesce( x, value( y, (SqmExpression) x ) ); } @@ -2063,7 +2073,6 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext, public > SqmPredicate between(Expression value, Expression lower, Expression upper) { assertComparable( value, lower ); assertComparable( value, upper ); - //noinspection unchecked return new SqmBetweenPredicate( (SqmExpression) value, (SqmExpression) lower, @@ -2074,7 +2083,6 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext, } @Override - @SuppressWarnings("unchecked") public > SqmPredicate between(Expression value, Y lower, Y upper) { final SqmExpression valueExpression = (SqmExpression) value; final SqmExpression lowerExpr = value( lower, valueExpression ); @@ -2208,7 +2216,6 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext, } @Override - @SuppressWarnings({ "unchecked", "rawtypes" }) public > SqmPredicate greaterThan(Expression x, Y y) { final SqmExpression yExpr = value( y, (SqmExpression) x ); assertComparable( x, yExpr ); @@ -2232,7 +2239,6 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext, } @Override - @SuppressWarnings({ "unchecked", "rawtypes" }) public > SqmPredicate greaterThanOrEqualTo(Expression x, Y y) { final SqmExpression yExpr = value( y, (SqmExpression) x ); assertComparable( x, yExpr ); diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/produce/function/ArgumentTypesValidator.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/produce/function/ArgumentTypesValidator.java index ab84ccc18a..d422955bf3 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/produce/function/ArgumentTypesValidator.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/produce/function/ArgumentTypesValidator.java @@ -23,6 +23,7 @@ import org.hibernate.query.sqm.tree.expression.SqmTrimSpecification; import org.hibernate.sql.ast.tree.SqlAstNode; import org.hibernate.sql.ast.tree.expression.Expression; import org.hibernate.type.JavaObjectType; +import org.hibernate.type.SqlTypes; import org.hibernate.type.descriptor.java.JavaType; import org.hibernate.type.descriptor.java.spi.JdbcTypeRecommendationException; import org.hibernate.type.descriptor.jdbc.JdbcTypeIndicators; @@ -200,7 +201,7 @@ public class ArgumentTypesValidator implements ArgumentsValidator { } break; case STRING: - if ( !isCharacterType(code) && code != ENUM_UNKNOWN_JDBC_TYPE ) { + if ( !isCharacterType(code) && code != SqlTypes.ENUM && code != ENUM_UNKNOWN_JDBC_TYPE) { throwError(type, javaType, functionName, count); } break; diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/sql/BaseSqmToSqlAstConverter.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/sql/BaseSqmToSqlAstConverter.java index f1fec3684a..5518d01000 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/sql/BaseSqmToSqlAstConverter.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/sql/BaseSqmToSqlAstConverter.java @@ -392,14 +392,11 @@ import org.hibernate.sql.results.internal.StandardEntityGraphTraversalStateImpl; import org.hibernate.type.BasicType; import org.hibernate.type.JavaObjectType; import org.hibernate.type.SqlTypes; -import org.hibernate.type.descriptor.converter.internal.OrdinalEnumValueConverter; import org.hibernate.type.descriptor.converter.spi.BasicValueConverter; -import org.hibernate.type.descriptor.java.EnumJavaType; import org.hibernate.type.descriptor.java.JavaType; import org.hibernate.type.descriptor.java.JavaTypeHelper; -import org.hibernate.type.descriptor.jdbc.JdbcType; import org.hibernate.type.descriptor.jdbc.JdbcTypeIndicators; -import org.hibernate.type.internal.ConvertedBasicTypeImpl; +import org.hibernate.type.internal.BasicTypeImpl; import org.hibernate.type.spi.TypeConfiguration; import org.hibernate.usertype.UserVersionType; import org.hibernate.usertype.internal.AbstractTimeZoneStorageCompositeUserType; @@ -410,6 +407,7 @@ import jakarta.persistence.TemporalType; import jakarta.persistence.metamodel.SingularAttribute; import jakarta.persistence.metamodel.Type; +import static java.util.Collections.singletonList; import static org.hibernate.generator.EventType.INSERT; import static org.hibernate.internal.util.NullnessHelper.coalesceSuppliedValues; import static org.hibernate.query.sqm.BinaryArithmeticOperator.ADD; @@ -2213,7 +2211,7 @@ public abstract class BaseSqmToSqlAstConverter extends Base if ( selectionNode instanceof SqmPath ) { prepareForSelection( (SqmPath) selectionNode ); } - resultProducers = Collections.singletonList( + resultProducers = singletonList( new AbstractMap.SimpleEntry<>( sqmSelection.getAlias(), (DomainResultProducer) selectionNode.accept( this ) @@ -4236,7 +4234,7 @@ public abstract class BaseSqmToSqlAstConverter extends Base final Expression expression = new SelfRenderingAggregateFunctionSqlAstExpression( functionDescriptor.getName(), functionDescriptor, - Collections.singletonList( new QueryLiteral<>( 1, integerType ) ), + singletonList( new QueryLiteral<>( 1, integerType ) ), null, integerType, integerType @@ -4585,7 +4583,7 @@ public abstract class BaseSqmToSqlAstConverter extends Base arguments = subQueryColumns; } else { - arguments = Collections.singletonList( new SqlTuple( subQueryColumns, modelPart ) ); + arguments = singletonList( new SqlTuple( subQueryColumns, modelPart ) ); } final Expression expression = new SelfRenderingAggregateFunctionSqlAstExpression( functionDescriptor.getName(), @@ -4707,7 +4705,7 @@ public abstract class BaseSqmToSqlAstConverter extends Base return new SelfRenderingFunctionSqlAstExpression( pathName, (sqlAppender, sqlAstArguments, walker) -> sqlAstArguments.get( 0 ).accept( walker ), - Collections.singletonList( + singletonList( new ColumnReference( identifierVariable, tableReference.getColumnNames().get( 0 ), @@ -4871,9 +4869,9 @@ public abstract class BaseSqmToSqlAstConverter extends Base mappingModelExpressible = determineCurrentExpressible( literal ); } if ( mappingModelExpressible instanceof BasicValuedMapping ) { - return new QueryLiteral<>( null, (BasicValuedMapping) mappingModelExpressible); + return new QueryLiteral<>( null, (BasicValuedMapping) mappingModelExpressible ); } - final MappingModelExpressible keyExpressible = getKeyExpressible(mappingModelExpressible); + final MappingModelExpressible keyExpressible = getKeyExpressible( mappingModelExpressible ); if ( keyExpressible == null ) { // Default to the Object type return new QueryLiteral<>( null, basicType( Object.class ) ); @@ -4897,10 +4895,7 @@ public abstract class BaseSqmToSqlAstConverter extends Base else { keyExpressible.forEachJdbcType( (index, jdbcMapping) -> expressions.add( - new QueryLiteral<>( - null, - (BasicValuedMapping) jdbcMapping - ) + new QueryLiteral<>( null, (BasicValuedMapping) jdbcMapping ) ) ); } @@ -4951,10 +4946,7 @@ public abstract class BaseSqmToSqlAstConverter extends Base ) ); } - return new QueryLiteral<>( - sqlLiteralValue, - basicValuedMapping - ); + return new QueryLiteral<>( sqlLiteralValue, basicValuedMapping ); } } @@ -6472,35 +6464,27 @@ public abstract class BaseSqmToSqlAstConverter extends Base @Override public Object visitEnumLiteral(SqmEnumLiteral sqmEnumLiteral) { - final BasicValuedMapping inferrableType = (BasicValuedMapping) resolveInferredType(); - if ( inferrableType != null ) { - final Object jdbcValue = inferrableType.getJdbcMapping().convertToRelationalValue( sqmEnumLiteral.getEnumValue() ); - return new QueryLiteral<>( jdbcValue, inferrableType ); + final BasicValuedMapping inferredType = (BasicValuedMapping) resolveInferredType(); + if ( inferredType != null ) { + return new QueryLiteral<>( + inferredType.getJdbcMapping().convertToRelationalValue( sqmEnumLiteral.getEnumValue() ), + inferredType + ); } else { // This can only happen when selecting an enum literal, in which case we default to ordinal encoding - final EnumJavaType enumJtd = sqmEnumLiteral.getExpressibleJavaType(); - final TypeConfiguration typeConfiguration = getTypeConfiguration(); - final JdbcType jdbcType = typeConfiguration.getJdbcTypeRegistry().getDescriptor( SqlTypes.SMALLINT ); - final JavaType relationalJtd = typeConfiguration.getJavaTypeRegistry().getDescriptor( Integer.class ); - - return queryLiteral( sqmEnumLiteral, enumJtd, typeConfiguration, jdbcType, relationalJtd ); + return queryLiteral( sqmEnumLiteral, getTypeConfiguration() ); } } - private static , N extends Number> QueryLiteral queryLiteral( - SqmEnumLiteral sqmEnumLiteral, - EnumJavaType enumJtd, - TypeConfiguration typeConfiguration, - JdbcType jdbcType, - JavaType relationalJtd) { + private static > QueryLiteral queryLiteral( + SqmEnumLiteral sqmEnumLiteral, + TypeConfiguration typeConfiguration) { return new QueryLiteral<>( - sqmEnumLiteral.getEnumValue().ordinal(), - new ConvertedBasicTypeImpl<>( - null, - "Query literal implicit Enum type descriptor", - jdbcType, - new OrdinalEnumValueConverter<>( enumJtd, jdbcType, relationalJtd ) + sqmEnumLiteral.getEnumValue(), + new BasicTypeImpl<>( + sqmEnumLiteral.getExpressibleJavaType(), + typeConfiguration.getJdbcTypeRegistry().getDescriptor( SqlTypes.SMALLINT ) ) ); } diff --git a/hibernate-core/src/main/java/org/hibernate/sql/ast/tree/expression/QueryLiteral.java b/hibernate-core/src/main/java/org/hibernate/sql/ast/tree/expression/QueryLiteral.java index 1e0ca9848e..aadefc41f4 100644 --- a/hibernate-core/src/main/java/org/hibernate/sql/ast/tree/expression/QueryLiteral.java +++ b/hibernate-core/src/main/java/org/hibernate/sql/ast/tree/expression/QueryLiteral.java @@ -13,7 +13,6 @@ import org.hibernate.metamodel.mapping.BasicValuedMapping; import org.hibernate.metamodel.mapping.JdbcMapping; import org.hibernate.query.sqm.sql.internal.DomainResultProducer; import org.hibernate.sql.ast.SqlAstWalker; -import org.hibernate.sql.ast.spi.SqlExpressionResolver; import org.hibernate.sql.ast.spi.SqlSelection; import org.hibernate.sql.exec.spi.ExecutionContext; import org.hibernate.sql.exec.spi.JdbcParameterBindings; @@ -33,7 +32,6 @@ public class QueryLiteral implements Literal, DomainResultProducer { private final BasicValuedMapping type; public QueryLiteral(T value, BasicValuedMapping type) { - assert value == null || type.getJdbcMapping().getJdbcJavaType().isInstance( value ); this.value = value; this.type = type; } @@ -62,17 +60,16 @@ public class QueryLiteral implements Literal, DomainResultProducer { public DomainResult createDomainResult( String resultVariable, DomainResultCreationState creationState) { - final SqlExpressionResolver sqlExpressionResolver = creationState.getSqlAstCreationState() - .getSqlExpressionResolver(); - final SqlSelection sqlSelection = sqlExpressionResolver.resolveSqlSelection( - this, - type.getJdbcMapping().getJdbcJavaType(), - null, - creationState.getSqlAstCreationState() - .getCreationContext() - .getSessionFactory() - .getTypeConfiguration() - ); + final SqlSelection sqlSelection = creationState.getSqlAstCreationState().getSqlExpressionResolver() + .resolveSqlSelection( + this, + type.getJdbcMapping().getJdbcJavaType(), + null, + creationState.getSqlAstCreationState() + .getCreationContext() + .getSessionFactory() + .getTypeConfiguration() + ); return new BasicResult<>( sqlSelection.getValuesArrayPosition(), diff --git a/hibernate-core/src/main/java/org/hibernate/type/BasicType.java b/hibernate-core/src/main/java/org/hibernate/type/BasicType.java index ad4063f30d..c306b88d0b 100644 --- a/hibernate-core/src/main/java/org/hibernate/type/BasicType.java +++ b/hibernate-core/src/main/java/org/hibernate/type/BasicType.java @@ -159,6 +159,15 @@ public interface BasicType extends Type, BasicDomainType, MappingType, Bas checkCondition = getJdbcType().getCheckCondition( columnName, getMappedJavaType(), + valueConverter, + dialect + ); + } + if ( checkCondition == null ) { + checkCondition = getMappedJavaType().getCheckCondition( + columnName, + getJdbcType(), + valueConverter, dialect ); } diff --git a/hibernate-core/src/main/java/org/hibernate/type/SqlTypes.java b/hibernate-core/src/main/java/org/hibernate/type/SqlTypes.java index 47ea541af1..dde7e9feb6 100644 --- a/hibernate-core/src/main/java/org/hibernate/type/SqlTypes.java +++ b/hibernate-core/src/main/java/org/hibernate/type/SqlTypes.java @@ -522,6 +522,13 @@ public class SqlTypes { */ public static final int GEOGRAPHY = 3250; + /** + * A type code representing a SQL {@code ENUM} type. + * + * @since 6.3 + */ + public static final int ENUM = 6000; + private SqlTypes() { } 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 d7be94b2bc..2151cea53a 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 @@ -10,7 +10,7 @@ package org.hibernate.type.descriptor.converter.internal; * @author Gavin King */ public class EnumHelper { - public static final String[] getEnumeratedValues(Class> enumClass) { + public static String[] getEnumeratedValues(Class> enumClass) { Enum[] values = enumClass.getEnumConstants(); String[] names = new String[values.length]; for ( int i = 0; i < values.length; i++ ) { diff --git a/hibernate-core/src/main/java/org/hibernate/type/descriptor/converter/internal/NamedEnumValueConverter.java b/hibernate-core/src/main/java/org/hibernate/type/descriptor/converter/internal/NamedEnumValueConverter.java index 99be8f544b..771a970876 100644 --- a/hibernate-core/src/main/java/org/hibernate/type/descriptor/converter/internal/NamedEnumValueConverter.java +++ b/hibernate-core/src/main/java/org/hibernate/type/descriptor/converter/internal/NamedEnumValueConverter.java @@ -8,23 +8,20 @@ package org.hibernate.type.descriptor.converter.internal; import java.io.Serializable; -import org.hibernate.boot.model.relational.AuxiliaryDatabaseObject; -import org.hibernate.boot.model.relational.NamedAuxiliaryDatabaseObject; -import org.hibernate.boot.model.relational.Namespace; -import org.hibernate.dialect.Dialect; import org.hibernate.type.descriptor.converter.spi.EnumValueConverter; import org.hibernate.type.descriptor.java.EnumJavaType; import org.hibernate.type.descriptor.java.JavaType; import org.hibernate.type.descriptor.jdbc.JdbcType; -import static java.util.Collections.emptySet; - /** * BasicValueConverter handling the conversion of an enum based on * JPA {@link jakarta.persistence.EnumType#STRING} strategy (storing the name) * * @author Steve Ebersole + * + * @deprecated we no longer use converters to handle enum mappings */ +@Deprecated(since="6.3", forRemoval=true) public class NamedEnumValueConverter> implements EnumValueConverter, Serializable { private final EnumJavaType domainTypeDescriptor; private final JdbcType jdbcType; @@ -68,28 +65,4 @@ public class NamedEnumValueConverter> implements EnumValueConv public String toSqlLiteral(Object value) { return "'" + ( (Enum) value ).name() + "'"; } - - @Override - public String getCheckCondition(String columnName, JdbcType jdbcType, Dialect dialect) { - return dialect.getCheckCondition( columnName, getDomainJavaType().getJavaTypeClass() ); - } - - @Override - public String getSpecializedTypeDeclaration(JdbcType jdbcType, Dialect dialect) { - return dialect.getEnumTypeDeclaration( getDomainJavaType().getJavaTypeClass() ); - } - - @Override - public AuxiliaryDatabaseObject getAuxiliaryDatabaseObject(JdbcType jdbcType, Dialect dialect, Namespace defaultNamespace) { - Class> enumClass = getDomainJavaType().getJavaTypeClass(); - String name = enumClass.getSimpleName(); - String[] create = dialect.getCreateEnumTypeCommand( enumClass ); - if ( create != null ) { - String[] drop = new String[] { "drop type " + name + " cascade" }; //TODO: move to Dialect - return new NamedAuxiliaryDatabaseObject( name, defaultNamespace, create, drop, emptySet(), true ); - } - else { - return null; - } - } } diff --git a/hibernate-core/src/main/java/org/hibernate/type/descriptor/converter/internal/NativeEnumValueConverter.java b/hibernate-core/src/main/java/org/hibernate/type/descriptor/converter/internal/NativeEnumValueConverter.java deleted file mode 100644 index 2335e15945..0000000000 --- a/hibernate-core/src/main/java/org/hibernate/type/descriptor/converter/internal/NativeEnumValueConverter.java +++ /dev/null @@ -1,97 +0,0 @@ -/* - * 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.hibernate.type.descriptor.converter.internal; - -import org.hibernate.boot.model.relational.AuxiliaryDatabaseObject; -import org.hibernate.boot.model.relational.NamedAuxiliaryDatabaseObject; -import org.hibernate.boot.model.relational.Namespace; -import org.hibernate.dialect.Dialect; -import org.hibernate.type.descriptor.converter.spi.EnumValueConverter; -import org.hibernate.type.descriptor.java.EnumJavaType; -import org.hibernate.type.descriptor.java.JavaType; -import org.hibernate.type.descriptor.jdbc.JdbcType; - -import java.io.Serializable; - -import static java.util.Collections.emptySet; - -/** - * BasicValueConverter handling the conversion of an enum based on - * JPA {@link jakarta.persistence.EnumType#STRING} strategy (storing the name) - * - * @author Steve Ebersole - */ -public class NativeEnumValueConverter> implements EnumValueConverter, Serializable { - private final EnumJavaType domainTypeDescriptor; - private final JdbcType jdbcType; - private final JavaType relationalTypeDescriptor; - - public NativeEnumValueConverter( - EnumJavaType domainTypeDescriptor, - JdbcType jdbcType, - JavaType relationalTypeDescriptor) { - this.domainTypeDescriptor = domainTypeDescriptor; - this.jdbcType = jdbcType; - this.relationalTypeDescriptor = relationalTypeDescriptor; - } - - @Override - public EnumJavaType getDomainJavaType() { - return domainTypeDescriptor; - } - - @Override - public JavaType getRelationalJavaType() { - return relationalTypeDescriptor; - } - - @Override - public E toDomainValue(Object relationalForm) { - return relationalForm instanceof String - ? domainTypeDescriptor.fromName( (String) relationalForm ) - : (E) relationalForm; - } - - @Override - public Object toRelationalValue(E domainForm) { - return domainForm; - } - - @Override - public int getJdbcTypeCode() { - return jdbcType.getDefaultSqlTypeCode(); - } - - @Override - public String toSqlLiteral(Object value) { - return "'" + ( (Enum) value ).name() + "'"; - } - - @Override - public String getCheckCondition(String columnName, JdbcType jdbcType, Dialect dialect) { - return dialect.getCheckCondition( columnName, getDomainJavaType().getJavaTypeClass() ); - } - - @Override - public String getSpecializedTypeDeclaration(JdbcType jdbcType, Dialect dialect) { - return dialect.getEnumTypeDeclaration( getDomainJavaType().getJavaTypeClass() ); - } - - @Override - public AuxiliaryDatabaseObject getAuxiliaryDatabaseObject(JdbcType jdbcType, Dialect dialect, Namespace defaultNamespace) { - Class> enumClass = getDomainJavaType().getJavaTypeClass(); - String name = enumClass.getSimpleName(); - String[] create = dialect.getCreateEnumTypeCommand( enumClass ); - if ( create != null ) { - String[] drop = new String[] { "drop type " + name + " cascade" }; //TODO: move to Dialect - return new NamedAuxiliaryDatabaseObject( name, defaultNamespace, create, drop, emptySet(), true ); - } - else { - return null; - } - } -} diff --git a/hibernate-core/src/main/java/org/hibernate/type/descriptor/converter/internal/OrdinalEnumValueConverter.java b/hibernate-core/src/main/java/org/hibernate/type/descriptor/converter/internal/OrdinalEnumValueConverter.java index 8627b7d08a..ad15cd4516 100644 --- a/hibernate-core/src/main/java/org/hibernate/type/descriptor/converter/internal/OrdinalEnumValueConverter.java +++ b/hibernate-core/src/main/java/org/hibernate/type/descriptor/converter/internal/OrdinalEnumValueConverter.java @@ -8,7 +8,6 @@ package org.hibernate.type.descriptor.converter.internal; import java.io.Serializable; -import org.hibernate.dialect.Dialect; import org.hibernate.type.descriptor.converter.spi.EnumValueConverter; import org.hibernate.type.descriptor.java.EnumJavaType; import org.hibernate.type.descriptor.java.JavaType; @@ -19,7 +18,10 @@ import org.hibernate.type.descriptor.jdbc.JdbcType; * JPA {@link jakarta.persistence.EnumType#ORDINAL} strategy (storing the ordinal) * * @author Steve Ebersole + * + * @deprecated we no longer use converters to handle enum mappings */ +@Deprecated(since="6.3", forRemoval=true) public class OrdinalEnumValueConverter, N extends Number> implements EnumValueConverter, Serializable { private final EnumJavaType enumJavaType; @@ -64,10 +66,4 @@ public class OrdinalEnumValueConverter, N extends Number> impl public String toSqlLiteral(Object value) { return Integer.toString( ( (Enum) value ).ordinal() ); } - - @Override - public String getCheckCondition(String columnName, JdbcType jdbcType, Dialect dialect) { - int max = getDomainJavaType().getJavaTypeClass().getEnumConstants().length - 1; - return dialect.getCheckCondition( columnName, 0, max ); - } } diff --git a/hibernate-core/src/main/java/org/hibernate/type/descriptor/converter/spi/BasicValueConverter.java b/hibernate-core/src/main/java/org/hibernate/type/descriptor/converter/spi/BasicValueConverter.java index 1ff1fb34f1..183e0e54f1 100644 --- a/hibernate-core/src/main/java/org/hibernate/type/descriptor/converter/spi/BasicValueConverter.java +++ b/hibernate-core/src/main/java/org/hibernate/type/descriptor/converter/spi/BasicValueConverter.java @@ -7,8 +7,6 @@ package org.hibernate.type.descriptor.converter.spi; import org.hibernate.Incubating; -import org.hibernate.boot.model.relational.AuxiliaryDatabaseObject; -import org.hibernate.boot.model.relational.Namespace; import org.hibernate.dialect.Dialect; import org.hibernate.type.descriptor.java.JavaType; import org.hibernate.type.descriptor.jdbc.JdbcType; @@ -68,9 +66,4 @@ public interface BasicValueConverter { default String getSpecializedTypeDeclaration(JdbcType jdbcType, Dialect dialect) { return null; } - - @Incubating - default AuxiliaryDatabaseObject getAuxiliaryDatabaseObject(JdbcType jdbcType, Dialect dialect, Namespace defaultNamespace) { - return null; - } } 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 f0bc00c495..74af231edc 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 @@ -9,14 +9,15 @@ package org.hibernate.type.descriptor.java; import jakarta.persistence.EnumType; import org.hibernate.AssertionFailure; +import org.hibernate.dialect.Dialect; import org.hibernate.type.descriptor.WrapperOptions; +import org.hibernate.type.descriptor.converter.spi.BasicValueConverter; import org.hibernate.type.descriptor.jdbc.JdbcType; import org.hibernate.type.descriptor.jdbc.JdbcTypeIndicators; -import org.hibernate.type.descriptor.jdbc.NativeEnumJdbcType; -import org.hibernate.type.descriptor.jdbc.spi.JdbcTypeRegistry; import static jakarta.persistence.EnumType.ORDINAL; import static org.hibernate.type.SqlTypes.CHAR; +import static org.hibernate.type.SqlTypes.ENUM; import static org.hibernate.type.SqlTypes.NCHAR; import static org.hibernate.type.SqlTypes.NVARCHAR; import static org.hibernate.type.SqlTypes.SMALLINT; @@ -35,7 +36,6 @@ public class EnumJavaType> extends AbstractClassJavaType { @Override public JdbcType getRecommendedJdbcType(JdbcTypeIndicators context) { - final JdbcTypeRegistry registry = context.getTypeConfiguration().getJdbcTypeRegistry(); final EnumType type = context.getEnumeratedType(); int sqlType; switch ( type == null ? ORDINAL : type ) { @@ -44,7 +44,7 @@ public class EnumJavaType> extends AbstractClassJavaType { break; case STRING: if ( context.getDialect().hasNativeEnums() ) { - return NativeEnumJdbcType.INSTANCE; + sqlType = ENUM; } else if ( context.getColumnLength() == 1 ) { sqlType = context.isNationalized() ? NCHAR : CHAR; @@ -56,7 +56,7 @@ public class EnumJavaType> extends AbstractClassJavaType { default: throw new AssertionFailure("unknown EnumType"); } - return registry.getDescriptor( sqlType ); + return context.getTypeConfiguration().getJdbcTypeRegistry().getDescriptor( sqlType ); } public boolean hasManyValues() { @@ -254,4 +254,21 @@ public class EnumJavaType> extends AbstractClassJavaType { } } + @Override + public String getCheckCondition(String columnName, JdbcType jdbcType, BasicValueConverter converter, Dialect dialect) { + if ( converter != null ) { + //TODO: actually convert the enum values to create the check constraint + return null; + } + else if ( jdbcType.isInteger() ) { + int max = getJavaTypeClass().getEnumConstants().length - 1; + return dialect.getCheckCondition( columnName, 0, max ); + } + else if ( jdbcType.isString() ) { + return dialect.getCheckCondition( columnName, getJavaTypeClass() ); + } + else { + return null; + } + } } diff --git a/hibernate-core/src/main/java/org/hibernate/type/descriptor/java/JavaType.java b/hibernate-core/src/main/java/org/hibernate/type/descriptor/java/JavaType.java index 48a76f2118..ad5cc162f7 100644 --- a/hibernate-core/src/main/java/org/hibernate/type/descriptor/java/JavaType.java +++ b/hibernate-core/src/main/java/org/hibernate/type/descriptor/java/JavaType.java @@ -21,6 +21,7 @@ import org.hibernate.internal.util.ReflectHelper; import org.hibernate.internal.util.compare.ComparableComparator; import org.hibernate.sql.ast.spi.SqlAppender; import org.hibernate.type.descriptor.WrapperOptions; +import org.hibernate.type.descriptor.converter.spi.BasicValueConverter; import org.hibernate.type.descriptor.jdbc.JdbcType; import org.hibernate.type.descriptor.jdbc.JdbcTypeIndicators; import org.hibernate.type.spi.TypeConfiguration; @@ -332,4 +333,18 @@ public interface JavaType extends Serializable { return false; } + /** + * The check constraint that should be added to the column + * definition in generated DDL. + * + * @param columnName the name of the column + * @param jdbcType the {@link JdbcType} of the mapped column + * @param converter the converter, if any, or null + * @param dialect the SQL {@link Dialect} + * @return a check constraint condition or null + * @since 6.2 + */ + default String getCheckCondition(String columnName, JdbcType jdbcType, BasicValueConverter converter, Dialect dialect) { + return null; + } } diff --git a/hibernate-core/src/main/java/org/hibernate/type/descriptor/jdbc/IntegerJdbcType.java b/hibernate-core/src/main/java/org/hibernate/type/descriptor/jdbc/IntegerJdbcType.java index fd19db84ca..3a235a8f58 100644 --- a/hibernate-core/src/main/java/org/hibernate/type/descriptor/jdbc/IntegerJdbcType.java +++ b/hibernate-core/src/main/java/org/hibernate/type/descriptor/jdbc/IntegerJdbcType.java @@ -15,7 +15,6 @@ import java.sql.Types; import org.hibernate.type.descriptor.ValueBinder; import org.hibernate.type.descriptor.ValueExtractor; import org.hibernate.type.descriptor.WrapperOptions; -import org.hibernate.type.descriptor.java.BasicJavaType; import org.hibernate.type.descriptor.java.JavaType; import org.hibernate.type.descriptor.jdbc.internal.JdbcLiteralFormatterNumericData; import org.hibernate.type.spi.TypeConfiguration; diff --git a/hibernate-core/src/main/java/org/hibernate/type/descriptor/jdbc/JdbcType.java b/hibernate-core/src/main/java/org/hibernate/type/descriptor/jdbc/JdbcType.java index dd64edc7e5..13ce4ec918 100644 --- a/hibernate-core/src/main/java/org/hibernate/type/descriptor/jdbc/JdbcType.java +++ b/hibernate-core/src/main/java/org/hibernate/type/descriptor/jdbc/JdbcType.java @@ -12,6 +12,7 @@ import java.sql.SQLException; import java.sql.Types; import org.hibernate.Incubating; +import org.hibernate.boot.spi.InFlightMetadataCollector; import org.hibernate.dialect.Dialect; import org.hibernate.engine.jdbc.Size; import org.hibernate.query.sqm.CastType; @@ -22,6 +23,7 @@ import org.hibernate.type.SqlTypes; import org.hibernate.type.descriptor.ValueBinder; import org.hibernate.type.descriptor.ValueExtractor; import org.hibernate.type.descriptor.WrapperOptions; +import org.hibernate.type.descriptor.converter.spi.BasicValueConverter; import org.hibernate.type.descriptor.java.JavaType; import org.hibernate.type.descriptor.sql.spi.DdlTypeRegistry; import org.hibernate.type.spi.TypeConfiguration; @@ -155,12 +157,13 @@ public interface JdbcType extends Serializable { * definition in generated DDL. * * @param columnName the name of the column - * @param javaType the {@link JavaType} of the mapped column - * @param dialect the SQL {@link Dialect} + * @param javaType the {@link JavaType} of the mapped column + * @param converter the converter, if any, or null + * @param dialect the SQL {@link Dialect} * @return a check constraint condition or null * @since 6.2 */ - default String getCheckCondition(String columnName, JavaType javaType, Dialect dialect) { + default String getCheckCondition(String columnName, JavaType javaType, BasicValueConverter converter, Dialect dialect) { return null; } @@ -322,4 +325,8 @@ public interface JdbcType extends Serializable { default void registerOutParameter(CallableStatement callableStatement, int index) throws SQLException { callableStatement.registerOutParameter( index, getJdbcTypeCode() ); } + + @Incubating + default void addAuxiliaryDatabaseObjects(JavaType javaType, InFlightMetadataCollector metadataCollector) { + } } diff --git a/hibernate-core/src/main/java/org/hibernate/type/descriptor/jdbc/NativeEnumJdbcType.java b/hibernate-core/src/main/java/org/hibernate/type/descriptor/jdbc/NativeEnumJdbcType.java deleted file mode 100644 index de2eaaac1f..0000000000 --- a/hibernate-core/src/main/java/org/hibernate/type/descriptor/jdbc/NativeEnumJdbcType.java +++ /dev/null @@ -1,55 +0,0 @@ -package org.hibernate.type.descriptor.jdbc; - -import org.hibernate.type.SqlTypes; -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 java.sql.CallableStatement; -import java.sql.PreparedStatement; -import java.sql.ResultSet; -import java.sql.SQLException; - -public class NativeEnumJdbcType extends VarcharJdbcType { - - public static final NativeEnumJdbcType INSTANCE = new NativeEnumJdbcType(); - - @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.setObject( index, value, SqlTypes.OTHER ); - } - - @Override - protected void doBind(CallableStatement st, X value, String name, WrapperOptions options) - throws SQLException { - st.setObject( name, value, SqlTypes.OTHER ); - } - }; - } - - @Override - @SuppressWarnings("unchecked") - public ValueExtractor getExtractor(JavaType javaType) { - return new BasicExtractor<>( javaType, this ) { - @Override - protected X doExtract(ResultSet rs, int paramIndex, WrapperOptions options) throws SQLException { - return (X) rs.getObject( paramIndex ); - } - - @Override - protected X doExtract(CallableStatement statement, int index, WrapperOptions options) throws SQLException { - return (X) statement.getObject( index ); - } - - @Override - protected X doExtract(CallableStatement statement, String name, WrapperOptions options) throws SQLException { - return (X) statement.getObject( name ); - } - }; - } -} diff --git a/hibernate-core/src/main/java/org/hibernate/type/descriptor/jdbc/OracleJsonBlobJdbcType.java b/hibernate-core/src/main/java/org/hibernate/type/descriptor/jdbc/OracleJsonBlobJdbcType.java index a8bdb178fb..78a15af245 100644 --- a/hibernate-core/src/main/java/org/hibernate/type/descriptor/jdbc/OracleJsonBlobJdbcType.java +++ b/hibernate-core/src/main/java/org/hibernate/type/descriptor/jdbc/OracleJsonBlobJdbcType.java @@ -20,6 +20,7 @@ import org.hibernate.type.SqlTypes; import org.hibernate.type.descriptor.ValueBinder; import org.hibernate.type.descriptor.ValueExtractor; import org.hibernate.type.descriptor.WrapperOptions; +import org.hibernate.type.descriptor.converter.spi.BasicValueConverter; import org.hibernate.type.descriptor.java.JavaType; /** @@ -61,7 +62,7 @@ public class OracleJsonBlobJdbcType implements AggregateJdbcType { } @Override - public String getCheckCondition(String columnName, JavaType javaType, Dialect dialect) { + public String getCheckCondition(String columnName, JavaType javaType, BasicValueConverter converter, Dialect dialect) { return columnName + " is json"; } diff --git a/hibernate-core/src/main/java/org/hibernate/type/descriptor/jdbc/internal/JdbcTypeBaseline.java b/hibernate-core/src/main/java/org/hibernate/type/descriptor/jdbc/internal/JdbcTypeBaseline.java index 2a276c66e7..564d03a882 100644 --- a/hibernate-core/src/main/java/org/hibernate/type/descriptor/jdbc/internal/JdbcTypeBaseline.java +++ b/hibernate-core/src/main/java/org/hibernate/type/descriptor/jdbc/internal/JdbcTypeBaseline.java @@ -89,5 +89,8 @@ public class JdbcTypeBaseline { target.addDescriptor( new LongVarcharJdbcType(SqlTypes.LONG32NVARCHAR) ); target.addDescriptor( RowIdJdbcType.INSTANCE ); + + // by default, map named enums to varchar columns + target.addDescriptor( SqlTypes.ENUM, VarcharJdbcType.INSTANCE ); } } diff --git a/hibernate-core/src/main/java/org/hibernate/type/descriptor/sql/DdlType.java b/hibernate-core/src/main/java/org/hibernate/type/descriptor/sql/DdlType.java index 710c5b9a92..2c3ebd2974 100644 --- a/hibernate-core/src/main/java/org/hibernate/type/descriptor/sql/DdlType.java +++ b/hibernate-core/src/main/java/org/hibernate/type/descriptor/sql/DdlType.java @@ -36,32 +36,46 @@ public interface DdlType extends Serializable { */ int getSqlTypeCode(); + default String getTypeName(Size columnSize, Class returnedClass) { + return getTypeName( columnSize ); + } + /** * Returns the default type name without precision/length and scale parameters. + * + * @deprecated not appropriate for named enum or array types */ + @Deprecated(since = "6.3") String getRawTypeName(); /** * Returns all type names without precision/length and scale parameters. + * + * @deprecated not appropriate for named enum or array types */ @Incubating + @Deprecated(since = "6.3") default String[] getRawTypeNames() { return new String[] { getRawTypeName() }; } - String getTypeNamePattern(); - /** * Return a type with length, precision, and scale specified by the given * {@linkplain Size size object}. + * + * @deprecated not appropriate for named enum or array types */ + @Deprecated(since = "6.3") default String getTypeName(Size size) { return getTypeName( size.getLength(), size.getPrecision(), size.getScale() ); } /** * Return a type with the given length, precision, and scale. + * + * @deprecated not appropriate for named enum or array types */ + @Deprecated(since = "6.3") String getTypeName(Long size, Integer precision, Integer scale); /** diff --git a/hibernate-core/src/main/java/org/hibernate/type/descriptor/sql/internal/DdlTypeImpl.java b/hibernate-core/src/main/java/org/hibernate/type/descriptor/sql/internal/DdlTypeImpl.java index 9846e22a25..25f257361f 100644 --- a/hibernate-core/src/main/java/org/hibernate/type/descriptor/sql/internal/DdlTypeImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/type/descriptor/sql/internal/DdlTypeImpl.java @@ -63,11 +63,6 @@ public class DdlTypeImpl implements DdlType { return typeNamePattern; } - @Override - public String getTypeNamePattern() { - return typeNamePattern; - } - @Override public String getTypeName(Long size, Integer precision, Integer scale) { return replace( typeNamePattern, size, precision, scale ); diff --git a/hibernate-core/src/main/java/org/hibernate/type/descriptor/sql/internal/NamedNativeEnumDdlTypeImpl.java b/hibernate-core/src/main/java/org/hibernate/type/descriptor/sql/internal/NamedNativeEnumDdlTypeImpl.java new file mode 100644 index 0000000000..6b75d11b07 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/type/descriptor/sql/internal/NamedNativeEnumDdlTypeImpl.java @@ -0,0 +1,57 @@ +/* + * 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.sql.internal; + +import org.hibernate.dialect.Dialect; +import org.hibernate.engine.jdbc.Size; +import org.hibernate.type.descriptor.java.JavaType; +import org.hibernate.type.descriptor.jdbc.JdbcType; +import org.hibernate.type.descriptor.sql.DdlType; + +import static org.hibernate.type.SqlTypes.ENUM; + +/** + * @author Gavin King + */ +public class NamedNativeEnumDdlTypeImpl implements DdlType { + private final Dialect dialect; + + public NamedNativeEnumDdlTypeImpl(Dialect dialect) { + this.dialect = dialect; + } + + @Override + public int getSqlTypeCode() { + return ENUM; + } + + @Override + public String getTypeName(Size columnSize, Class returnedClass) { + return dialect.getEnumTypeDeclaration( (Class>) returnedClass ); + } + + @Override + public String getRawTypeName() { + // this + return "enum"; + } + + @Override + public String getTypeName(Long size, Integer precision, Integer scale) { + throw new UnsupportedOperationException( "native enum type" ); + } + + @Override + public String getCastTypeName(JdbcType jdbcType, JavaType javaType) { + return dialect.getEnumTypeDeclaration( (Class>) javaType.getJavaType() ); + } + + @Override + public String getCastTypeName(JdbcType jdbcType, JavaType javaType, Long length, Integer precision, Integer scale) { + return dialect.getEnumTypeDeclaration( (Class>) javaType.getJavaType() ); + } +} diff --git a/hibernate-core/src/main/java/org/hibernate/type/descriptor/sql/internal/NativeEnumDdlTypeImpl.java b/hibernate-core/src/main/java/org/hibernate/type/descriptor/sql/internal/NativeEnumDdlTypeImpl.java new file mode 100644 index 0000000000..7e7a690a2d --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/type/descriptor/sql/internal/NativeEnumDdlTypeImpl.java @@ -0,0 +1,57 @@ +/* + * 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.sql.internal; + +import org.hibernate.dialect.Dialect; +import org.hibernate.engine.jdbc.Size; +import org.hibernate.type.descriptor.java.JavaType; +import org.hibernate.type.descriptor.jdbc.JdbcType; +import org.hibernate.type.descriptor.sql.DdlType; + +import static org.hibernate.type.SqlTypes.ENUM; + +/** + * @author Gavin King + */ +public class NativeEnumDdlTypeImpl implements DdlType { + private final Dialect dialect; + + public NativeEnumDdlTypeImpl(Dialect dialect) { + this.dialect = dialect; + } + + @Override + public int getSqlTypeCode() { + return ENUM; + } + + @Override + public String getTypeName(Size columnSize, Class returnedClass) { + return dialect.getEnumTypeDeclaration( (Class>) returnedClass ); + } + + @Override + public String getRawTypeName() { + // this + return "enum"; + } + + @Override + public String getTypeName(Long size, Integer precision, Integer scale) { + return "varchar(" + size + ")"; + } + + @Override + public String getCastTypeName(JdbcType jdbcType, JavaType javaType) { + return "varchar"; + } + + @Override + public String getCastTypeName(JdbcType jdbcType, JavaType javaType, Long length, Integer precision, Integer scale) { + return getTypeName( length, precision, scale ); + } +} diff --git a/hibernate-core/src/main/java/org/hibernate/type/descriptor/sql/spi/DdlTypeRegistry.java b/hibernate-core/src/main/java/org/hibernate/type/descriptor/sql/spi/DdlTypeRegistry.java index 9ded8ec141..9781eb0046 100644 --- a/hibernate-core/src/main/java/org/hibernate/type/descriptor/sql/spi/DdlTypeRegistry.java +++ b/hibernate-core/src/main/java/org/hibernate/type/descriptor/sql/spi/DdlTypeRegistry.java @@ -16,6 +16,7 @@ import org.hibernate.HibernateException; import org.hibernate.dialect.Dialect; import org.hibernate.engine.jdbc.Size; import org.hibernate.type.SqlTypes; +import org.hibernate.type.Type; import org.hibernate.type.descriptor.JdbcTypeNameMapper; import org.hibernate.type.descriptor.sql.DdlType; import org.hibernate.type.spi.TypeConfiguration; @@ -179,11 +180,28 @@ public class DdlTypeRegistry implements Serializable { * * @return the associated type name with the smallest capacity that accommodates * the given size, if available, and the default type name otherwise + * + * @deprecated not appropriate for named enum or array types */ + @Deprecated(since = "6.3") public String getTypeName(int typeCode, Size size) { return getTypeName( typeCode, size.getLength(), size.getPrecision(), size.getScale() ); } + public String getTypeName(int typeCode, Size columnSize, Type type) { + final DdlType descriptor = getDescriptor( typeCode ); + if ( descriptor == null ) { + throw new HibernateException( + String.format( + "No type mapping for org.hibernate.type.SqlTypes code: %s (%s)", + typeCode, + JdbcTypeNameMapper.getTypeName( typeCode ) + ) + ); + } + return descriptor.getTypeName( columnSize, type.getReturnedClass() ); + } + /** * Get the SQL type name for the specified {@link java.sql.Types JDBC type code} * and size, filling in the placemarkers {@code $l}, {@code $p}, and {@code $s} @@ -197,7 +215,10 @@ public class DdlTypeRegistry implements Serializable { * * @return the associated type name with the smallest capacity that accommodates * the given size, if available, and the default type name otherwise + * + * @deprecated not appropriate for named enum or array types */ + @Deprecated(since = "6.3") public String getTypeName(int typeCode, Long size, Integer precision, Integer scale) { final DdlType descriptor = getDescriptor( typeCode ); if ( descriptor == null ) { @@ -230,5 +251,4 @@ public class DdlTypeRegistry implements Serializable { return false; } - } diff --git a/hibernate-envers/src/main/java/org/hibernate/envers/configuration/internal/metadata/BasicMetadataGenerator.java b/hibernate-envers/src/main/java/org/hibernate/envers/configuration/internal/metadata/BasicMetadataGenerator.java index 68b8bbc31b..4e17279460 100644 --- a/hibernate-envers/src/main/java/org/hibernate/envers/configuration/internal/metadata/BasicMetadataGenerator.java +++ b/hibernate-envers/src/main/java/org/hibernate/envers/configuration/internal/metadata/BasicMetadataGenerator.java @@ -17,11 +17,9 @@ import org.hibernate.mapping.SimpleValue; import org.hibernate.mapping.Value; import org.hibernate.type.BasicType; import org.hibernate.type.ConvertedBasicType; -import org.hibernate.type.CustomType; import org.hibernate.type.EnumType; import org.hibernate.type.Type; import org.hibernate.type.descriptor.converter.internal.NamedEnumValueConverter; -import org.hibernate.type.descriptor.converter.spi.BasicValueConverter; import org.hibernate.type.descriptor.converter.spi.EnumValueConverter; /**