From 2661e5cd188ed6a6d86e7ae436d2a943a5cea2ed Mon Sep 17 00:00:00 2001 From: Christian Beikov Date: Wed, 24 Jan 2024 11:38:08 +0100 Subject: [PATCH] HHH-17662 Replace JdbcTypeConstructor uses for arrays with uniform resolve method --- .../dialect/CockroachLegacyDialect.java | 8 +- .../dialect/OracleLegacyDialect.java | 15 +- .../dialect/PostgreSQLLegacyDialect.java | 8 +- .../hibernate/dialect/CockroachDialect.java | 8 +- .../java/org/hibernate/dialect/Dialect.java | 28 ++-- .../OracleArrayJdbcTypeConstructor.java | 19 ++- .../org/hibernate/dialect/OracleDialect.java | 14 +- .../OracleNestedTableJdbcTypeConstructor.java | 19 ++- .../hibernate/dialect/PostgreSQLDialect.java | 8 +- .../java/AbstractArrayJavaType.java | 63 +------ .../java/spi/BasicCollectionJavaType.java | 52 +----- .../type/descriptor/jdbc/ArrayJdbcType.java | 4 +- .../descriptor/jdbc/spi/JdbcTypeRegistry.java | 154 ++++++++++++++++++ 13 files changed, 228 insertions(+), 172 deletions(-) diff --git a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/CockroachLegacyDialect.java b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/CockroachLegacyDialect.java index e6045033cb..6362e3a91b 100644 --- a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/CockroachLegacyDialect.java +++ b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/CockroachLegacyDialect.java @@ -300,15 +300,13 @@ public class CockroachLegacyDialect extends Dialect { } break; case ARRAY: - final JdbcTypeConstructor jdbcTypeConstructor = jdbcTypeRegistry.getConstructor( jdbcTypeCode ); // PostgreSQL names array types by prepending an underscore to the base name - if ( jdbcTypeConstructor != null && columnTypeName.charAt( 0 ) == '_' ) { + if ( columnTypeName.charAt( 0 ) == '_' ) { final String componentTypeName = columnTypeName.substring( 1 ); final Integer sqlTypeCode = resolveSqlTypeCode( componentTypeName, jdbcTypeRegistry.getTypeConfiguration() ); if ( sqlTypeCode != null ) { - return jdbcTypeConstructor.resolveType( - jdbcTypeRegistry.getTypeConfiguration(), - this, + return jdbcTypeRegistry.resolveTypeConstructorDescriptor( + jdbcTypeCode, jdbcTypeRegistry.getDescriptor( sqlTypeCode ), ColumnTypeInformation.EMPTY ); diff --git a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/OracleLegacyDialect.java b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/OracleLegacyDialect.java index 940dc94b81..d88fe3fc23 100644 --- a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/OracleLegacyDialect.java +++ b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/OracleLegacyDialect.java @@ -100,7 +100,6 @@ import org.hibernate.type.descriptor.java.PrimitiveByteArrayJavaType; import org.hibernate.type.descriptor.jdbc.AggregateJdbcType; import org.hibernate.type.descriptor.jdbc.BlobJdbcType; import org.hibernate.type.descriptor.jdbc.JdbcType; -import org.hibernate.type.descriptor.jdbc.JdbcTypeConstructor; import org.hibernate.type.descriptor.jdbc.OracleJsonBlobJdbcType; import org.hibernate.type.descriptor.jdbc.NullJdbcType; import org.hibernate.type.descriptor.jdbc.ObjectNullAsNullTypeJdbcType; @@ -760,15 +759,11 @@ public class OracleLegacyDialect extends Dialect { break; case ARRAY: if ( "MDSYS.SDO_ORDINATE_ARRAY".equals( columnTypeName ) ) { - final JdbcTypeConstructor jdbcTypeConstructor = jdbcTypeRegistry.getConstructor( jdbcTypeCode ); - if ( jdbcTypeConstructor != null ) { - return jdbcTypeConstructor.resolveType( - jdbcTypeRegistry.getTypeConfiguration(), - this, - jdbcTypeRegistry.getDescriptor( NUMERIC ), - ColumnTypeInformation.EMPTY - ); - } + return jdbcTypeRegistry.resolveTypeConstructorDescriptor( + jdbcTypeCode, + jdbcTypeRegistry.getDescriptor( NUMERIC ), + ColumnTypeInformation.EMPTY + ); } break; case Types.NUMERIC: diff --git a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/PostgreSQLLegacyDialect.java b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/PostgreSQLLegacyDialect.java index 502de8521c..f41b967337 100644 --- a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/PostgreSQLLegacyDialect.java +++ b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/PostgreSQLLegacyDialect.java @@ -328,15 +328,13 @@ public class PostgreSQLLegacyDialect extends Dialect { } break; case ARRAY: - final JdbcTypeConstructor jdbcTypeConstructor = jdbcTypeRegistry.getConstructor( jdbcTypeCode ); // PostgreSQL names array types by prepending an underscore to the base name - if ( jdbcTypeConstructor != null && columnTypeName.charAt( 0 ) == '_' ) { + if ( columnTypeName.charAt( 0 ) == '_' ) { final String componentTypeName = columnTypeName.substring( 1 ); final Integer sqlTypeCode = resolveSqlTypeCode( componentTypeName, jdbcTypeRegistry.getTypeConfiguration() ); if ( sqlTypeCode != null ) { - return jdbcTypeConstructor.resolveType( - jdbcTypeRegistry.getTypeConfiguration(), - this, + return jdbcTypeRegistry.resolveTypeConstructorDescriptor( + jdbcTypeCode, jdbcTypeRegistry.getDescriptor( sqlTypeCode ), ColumnTypeInformation.EMPTY ); diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/CockroachDialect.java b/hibernate-core/src/main/java/org/hibernate/dialect/CockroachDialect.java index 76490fb2bb..1dd0b09c3f 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/CockroachDialect.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/CockroachDialect.java @@ -318,15 +318,13 @@ public class CockroachDialect extends Dialect { } break; case ARRAY: - final JdbcTypeConstructor jdbcTypeConstructor = jdbcTypeRegistry.getConstructor( jdbcTypeCode ); // PostgreSQL names array types by prepending an underscore to the base name - if ( jdbcTypeConstructor != null && columnTypeName.charAt( 0 ) == '_' ) { + if ( columnTypeName.charAt( 0 ) == '_' ) { final String componentTypeName = columnTypeName.substring( 1 ); final Integer sqlTypeCode = resolveSqlTypeCode( componentTypeName, jdbcTypeRegistry.getTypeConfiguration() ); if ( sqlTypeCode != null ) { - return jdbcTypeConstructor.resolveType( - jdbcTypeRegistry.getTypeConfiguration(), - this, + return jdbcTypeRegistry.resolveTypeConstructorDescriptor( + jdbcTypeCode, jdbcTypeRegistry.getDescriptor( sqlTypeCode ), ColumnTypeInformation.EMPTY ); 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 82d74c52ee..4d041cd6ba 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/Dialect.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/Dialect.java @@ -725,22 +725,18 @@ public abstract class Dialect implements ConversionContext, TypeContributor, Fun int scale, JdbcTypeRegistry jdbcTypeRegistry) { if ( jdbcTypeCode == ARRAY ) { - final JdbcTypeConstructor jdbcTypeConstructor = jdbcTypeRegistry.getConstructor( jdbcTypeCode ); - if ( jdbcTypeConstructor != null ) { - // Special handling for array types, because we need the proper element/component type - // To determine the element JdbcType, we pass the database reported type to #resolveSqlTypeCode - final int arraySuffixIndex = columnTypeName.toLowerCase( Locale.ROOT ).indexOf( " array" ); - if ( arraySuffixIndex != -1 ) { - final String componentTypeName = columnTypeName.substring( 0, arraySuffixIndex ); - final Integer sqlTypeCode = resolveSqlTypeCode( componentTypeName, jdbcTypeRegistry.getTypeConfiguration() ); - if ( sqlTypeCode != null ) { - return jdbcTypeConstructor.resolveType( - jdbcTypeRegistry.getTypeConfiguration(), - this, - jdbcTypeRegistry.getDescriptor( sqlTypeCode ), - ColumnTypeInformation.EMPTY - ); - } + // Special handling for array types, because we need the proper element/component type + // To determine the element JdbcType, we pass the database reported type to #resolveSqlTypeCode + final int arraySuffixIndex = columnTypeName.toLowerCase( Locale.ROOT ).indexOf( " array" ); + if ( arraySuffixIndex != -1 ) { + final String componentTypeName = columnTypeName.substring( 0, arraySuffixIndex ); + final Integer sqlTypeCode = resolveSqlTypeCode( componentTypeName, jdbcTypeRegistry.getTypeConfiguration() ); + if ( sqlTypeCode != null ) { + return jdbcTypeRegistry.resolveTypeConstructorDescriptor( + jdbcTypeCode, + jdbcTypeRegistry.getDescriptor( sqlTypeCode ), + ColumnTypeInformation.EMPTY + ); } } } diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/OracleArrayJdbcTypeConstructor.java b/hibernate-core/src/main/java/org/hibernate/dialect/OracleArrayJdbcTypeConstructor.java index 280ded56d1..4818cac81b 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/OracleArrayJdbcTypeConstructor.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/OracleArrayJdbcTypeConstructor.java @@ -46,10 +46,21 @@ public class OracleArrayJdbcTypeConstructor implements JdbcTypeConstructor { JdbcType elementType, ColumnTypeInformation columnTypeInformation) { // a bit wrong, since columnTypeInformation.getTypeName() is typically null! - return new OracleArrayJdbcType( - elementType, - columnTypeInformation == null ? null : columnTypeInformation.getTypeName() - ); + String typeName = columnTypeInformation == null ? null : columnTypeInformation.getTypeName(); + if ( typeName == null || typeName.isBlank() ) { + Integer precision = null; + Integer scale = null; + if ( columnTypeInformation != null ) { + precision = columnTypeInformation.getColumnSize(); + scale = columnTypeInformation.getDecimalDigits(); + } + typeName = OracleArrayJdbcType.getTypeName( elementType.getJdbcRecommendedJavaTypeMapping( + precision, + scale, + typeConfiguration + ), dialect ); + } + return new OracleArrayJdbcType( elementType, typeName ); } @Override diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/OracleDialect.java b/hibernate-core/src/main/java/org/hibernate/dialect/OracleDialect.java index 44c7236ee2..6b45b68ae1 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/OracleDialect.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/OracleDialect.java @@ -799,15 +799,11 @@ public class OracleDialect extends Dialect { break; case ARRAY: if ( "MDSYS.SDO_ORDINATE_ARRAY".equals( columnTypeName ) ) { - final JdbcTypeConstructor jdbcTypeConstructor = jdbcTypeRegistry.getConstructor( jdbcTypeCode ); - if ( jdbcTypeConstructor != null ) { - return jdbcTypeConstructor.resolveType( - jdbcTypeRegistry.getTypeConfiguration(), - this, - jdbcTypeRegistry.getDescriptor( NUMERIC ), - ColumnTypeInformation.EMPTY - ); - } + return jdbcTypeRegistry.resolveTypeConstructorDescriptor( + jdbcTypeCode, + jdbcTypeRegistry.getDescriptor( NUMERIC ), + ColumnTypeInformation.EMPTY + ); } break; case NUMERIC: diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/OracleNestedTableJdbcTypeConstructor.java b/hibernate-core/src/main/java/org/hibernate/dialect/OracleNestedTableJdbcTypeConstructor.java index cc148c2b3f..7199ec1b32 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/OracleNestedTableJdbcTypeConstructor.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/OracleNestedTableJdbcTypeConstructor.java @@ -40,10 +40,21 @@ public class OracleNestedTableJdbcTypeConstructor implements JdbcTypeConstructor JdbcType elementType, ColumnTypeInformation columnTypeInformation) { // a bit wrong, since columnTypeInformation.getTypeName() is typically null! - return new OracleNestedTableJdbcType( - elementType, - columnTypeInformation == null ? null : columnTypeInformation.getTypeName() - ); + String typeName = columnTypeInformation == null ? null : columnTypeInformation.getTypeName(); + if ( typeName == null || typeName.isBlank() ) { + Integer precision = null; + Integer scale = null; + if ( columnTypeInformation != null ) { + precision = columnTypeInformation.getColumnSize(); + scale = columnTypeInformation.getDecimalDigits(); + } + typeName = OracleArrayJdbcType.getTypeName( elementType.getJdbcRecommendedJavaTypeMapping( + precision, + scale, + typeConfiguration + ), dialect ); + } + return new OracleNestedTableJdbcType( elementType, typeName ); } @Override 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 7cabad34af..2804ca1ecd 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/PostgreSQLDialect.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/PostgreSQLDialect.java @@ -347,15 +347,13 @@ public class PostgreSQLDialect extends Dialect { } break; case ARRAY: - final JdbcTypeConstructor jdbcTypeConstructor = jdbcTypeRegistry.getConstructor( jdbcTypeCode ); // PostgreSQL names array types by prepending an underscore to the base name - if ( jdbcTypeConstructor != null && columnTypeName.charAt( 0 ) == '_' ) { + if ( columnTypeName.charAt( 0 ) == '_' ) { final String componentTypeName = columnTypeName.substring( 1 ); final Integer sqlTypeCode = resolveSqlTypeCode( componentTypeName, jdbcTypeRegistry.getTypeConfiguration() ); if ( sqlTypeCode != null ) { - return jdbcTypeConstructor.resolveType( - jdbcTypeRegistry.getTypeConfiguration(), - this, + return jdbcTypeRegistry.resolveTypeConstructorDescriptor( + jdbcTypeCode, jdbcTypeRegistry.getDescriptor( sqlTypeCode ), ColumnTypeInformation.EMPTY ); diff --git a/hibernate-core/src/main/java/org/hibernate/type/descriptor/java/AbstractArrayJavaType.java b/hibernate-core/src/main/java/org/hibernate/type/descriptor/java/AbstractArrayJavaType.java index 1011e5ec6f..74f3c19836 100644 --- a/hibernate-core/src/main/java/org/hibernate/type/descriptor/java/AbstractArrayJavaType.java +++ b/hibernate-core/src/main/java/org/hibernate/type/descriptor/java/AbstractArrayJavaType.java @@ -17,9 +17,7 @@ import org.hibernate.type.BasicType; import org.hibernate.type.ConvertedBasicArrayType; import org.hibernate.type.descriptor.converter.spi.BasicValueConverter; import org.hibernate.type.descriptor.jdbc.JdbcType; -import org.hibernate.type.descriptor.jdbc.JdbcTypeConstructor; import org.hibernate.type.descriptor.jdbc.JdbcTypeIndicators; -import org.hibernate.type.descriptor.jdbc.spi.JdbcTypeRegistry; import org.hibernate.type.internal.BasicTypeImpl; import org.hibernate.type.spi.TypeConfiguration; @@ -41,11 +39,9 @@ public abstract class AbstractArrayJavaType extends AbstractClassJavaType< @Override public JdbcType getRecommendedJdbcType(JdbcTypeIndicators indicators) { // Always determine the recommended type to make sure this is a valid basic java type - return getArrayJdbcType( - indicators.getTypeConfiguration(), - indicators.getDialect(), + return indicators.getTypeConfiguration().getJdbcTypeRegistry().resolveTypeConstructorDescriptor( indicators.getPreferredSqlTypeCodeForArray(), - new BasicTypeImpl<>( getElementJavaType(), componentJavaType.getRecommendedJdbcType( indicators ) ), + new BasicTypeImpl<>( componentJavaType, componentJavaType.getRecommendedJdbcType( indicators ) ), ColumnTypeInformation.EMPTY ); } @@ -86,9 +82,7 @@ public abstract class AbstractArrayJavaType extends AbstractClassJavaType< final JavaType relationalJavaType = typeConfiguration.getJavaTypeRegistry().getDescriptor( convertedArrayClass ); return new ConvertedBasicArrayType<>( elementType, - getArrayJdbcType( - typeConfiguration, - dialect, + typeConfiguration.getJdbcTypeRegistry().resolveTypeConstructorDescriptor( stdIndicators.getExplicitJdbcTypeCode(), elementType, columnTypeInformation @@ -105,9 +99,7 @@ public abstract class AbstractArrayJavaType extends AbstractClassJavaType< BasicType elementType, ColumnTypeInformation columnTypeInformation, JdbcTypeIndicators stdIndicators) { - final JdbcType arrayJdbcType = getArrayJdbcType( - typeConfiguration, - dialect, + final JdbcType arrayJdbcType = typeConfiguration.getJdbcTypeRegistry().resolveTypeConstructorDescriptor( stdIndicators.getExplicitJdbcTypeCode(), elementType, columnTypeInformation @@ -117,53 +109,6 @@ public abstract class AbstractArrayJavaType extends AbstractClassJavaType< arrayJdbcType, () -> new BasicArrayType<>( elementType, arrayJdbcType, arrayJavaType ) ); -// return typeConfiguration.getBasicTypeRegistry().getRegisteredType( elementType.getName() ) == elementType -// ? typeConfiguration.standardBasicTypeForJavaType( -// arrayJavaType.getJavaType(), -// javaType -> basicArrayType( typeConfiguration, dialect, elementType, columnTypeInformation, stdIndicators, arrayJavaType ) -// ) -// : basicArrayType( typeConfiguration, dialect, elementType, columnTypeInformation, stdIndicators, arrayJavaType ); } -// BasicType basicArrayType( -// TypeConfiguration typeConfiguration, -// Dialect dialect, -// BasicType elementType, -// ColumnTypeInformation columnTypeInformation, -// JdbcTypeIndicators stdIndicators, -// JavaType javaType) { -// return new BasicArrayType<>( -// elementType, -// getArrayJdbcType( -// typeConfiguration, -// dialect, -// stdIndicators.getExplicitJdbcTypeCode(), -// elementType, -// columnTypeInformation -// ), -// javaType -// ); -// } - - static JdbcType getArrayJdbcType( - TypeConfiguration typeConfiguration, - Dialect dialect, - int preferredSqlTypeCodeForArray, - BasicType elementType, - ColumnTypeInformation columnTypeInformation) { - final JdbcTypeRegistry jdbcTypeRegistry = typeConfiguration.getJdbcTypeRegistry(); - final JdbcTypeConstructor arrayJdbcTypeConstructor = - jdbcTypeRegistry.getConstructor( preferredSqlTypeCodeForArray ); - if ( arrayJdbcTypeConstructor != null ) { - return arrayJdbcTypeConstructor.resolveType( - typeConfiguration, - dialect, - elementType, - columnTypeInformation - ); - } - else { - return jdbcTypeRegistry.getDescriptor( preferredSqlTypeCodeForArray ); - } - } } diff --git a/hibernate-core/src/main/java/org/hibernate/type/descriptor/java/spi/BasicCollectionJavaType.java b/hibernate-core/src/main/java/org/hibernate/type/descriptor/java/spi/BasicCollectionJavaType.java index 177d0ba5df..74eaabfbfb 100644 --- a/hibernate-core/src/main/java/org/hibernate/type/descriptor/java/spi/BasicCollectionJavaType.java +++ b/hibernate-core/src/main/java/org/hibernate/type/descriptor/java/spi/BasicCollectionJavaType.java @@ -10,11 +10,9 @@ import java.io.Serializable; import java.lang.reflect.Array; import java.lang.reflect.ParameterizedType; import java.sql.SQLException; -import java.sql.Types; import java.util.ArrayList; import java.util.Collection; import java.util.Iterator; -import java.util.function.Function; import org.hibernate.HibernateException; import org.hibernate.Incubating; @@ -27,7 +25,6 @@ import org.hibernate.internal.util.SerializationHelper; import org.hibernate.internal.util.collections.CollectionHelper; import org.hibernate.metamodel.CollectionClassification; import org.hibernate.tool.schema.extract.spi.ColumnTypeInformation; -import org.hibernate.type.BasicArrayType; import org.hibernate.type.BasicCollectionType; import org.hibernate.type.BasicPluralType; import org.hibernate.type.BasicType; @@ -40,9 +37,7 @@ import org.hibernate.type.descriptor.java.BasicPluralJavaType; import org.hibernate.type.descriptor.java.JavaType; import org.hibernate.type.descriptor.java.MutabilityPlan; import org.hibernate.type.descriptor.jdbc.JdbcType; -import org.hibernate.type.descriptor.jdbc.JdbcTypeConstructor; import org.hibernate.type.descriptor.jdbc.JdbcTypeIndicators; -import org.hibernate.type.descriptor.jdbc.spi.JdbcTypeRegistry; import org.hibernate.type.internal.BasicTypeImpl; import org.hibernate.type.spi.TypeConfiguration; @@ -73,11 +68,9 @@ public class BasicCollectionJavaType, E> extends Abstrac public JdbcType getRecommendedJdbcType(JdbcTypeIndicators indicators) { // Always determine the recommended type to make sure this is a valid basic java type // (even though we only use this inside the if block, we want it to throw here if something wrong) - return getArrayJdbcType( - indicators.getTypeConfiguration(), - indicators.getDialect(), + return indicators.getTypeConfiguration().getJdbcTypeRegistry().resolveTypeConstructorDescriptor( indicators.getPreferredSqlTypeCodeForArray(), - new BasicTypeImpl<>( getElementJavaType(), componentJavaType.getRecommendedJdbcType( indicators ) ), + new BasicTypeImpl<>( componentJavaType, componentJavaType.getRecommendedJdbcType( indicators ) ), ColumnTypeInformation.EMPTY ); } @@ -119,23 +112,11 @@ public class BasicCollectionJavaType, E> extends Abstrac } final BasicValueConverter valueConverter = elementType.getValueConverter(); if ( valueConverter == null ) { - final JdbcType arrayJdbcType = getArrayJdbcType( - typeConfiguration, - dialect, + final JdbcType arrayJdbcType = typeConfiguration.getJdbcTypeRegistry().resolveTypeConstructorDescriptor( stdIndicators.getPreferredSqlTypeCodeForArray(), elementType, columnTypeInformation ); - final Function, BasicType> creator = javaType -> { - - //noinspection unchecked,rawtypes - return new BasicCollectionType( elementType, arrayJdbcType, collectionJavaType ); - }; -// if ( typeConfiguration.getBasicTypeRegistry().getRegisteredType( elementType.getName() ) == elementType ) { -// return typeConfiguration.standardBasicTypeForJavaType( collectionJavaType.getJavaType(), creator ); -// } -// //noinspection unchecked -// return creator.apply( (JavaType) (JavaType) collectionJavaType ); return typeConfiguration.getBasicTypeRegistry().resolve( collectionJavaType, arrayJdbcType, @@ -149,9 +130,7 @@ public class BasicCollectionJavaType, E> extends Abstrac //noinspection unchecked,rawtypes return new ConvertedBasicCollectionType( elementType, - getArrayJdbcType( - typeConfiguration, - dialect, + typeConfiguration.getJdbcTypeRegistry().resolveTypeConstructorDescriptor( stdIndicators.getPreferredSqlTypeCodeForArray(), elementType, columnTypeInformation @@ -162,29 +141,6 @@ public class BasicCollectionJavaType, E> extends Abstrac } } - //TODO: copy/pasted from AbstractArrayJavaType - private static JdbcType getArrayJdbcType( - TypeConfiguration typeConfiguration, - Dialect dialect, - int preferredSqlTypeCodeForArray, - BasicType elementType, - ColumnTypeInformation columnTypeInformation) { - final JdbcTypeRegistry jdbcTypeRegistry = typeConfiguration.getJdbcTypeRegistry(); - final JdbcTypeConstructor arrayJdbcTypeConstructor = - jdbcTypeRegistry.getConstructor( preferredSqlTypeCodeForArray ); - if ( arrayJdbcTypeConstructor != null ) { - return arrayJdbcTypeConstructor.resolveType( - typeConfiguration, - dialect, - elementType, - columnTypeInformation - ); - } - else { - return jdbcTypeRegistry.getDescriptor( preferredSqlTypeCodeForArray ); - } - } - @Override public String extractLoggableRepresentation(C value) { if ( value == null ) { diff --git a/hibernate-core/src/main/java/org/hibernate/type/descriptor/jdbc/ArrayJdbcType.java b/hibernate-core/src/main/java/org/hibernate/type/descriptor/jdbc/ArrayJdbcType.java index f83ebd131e..1b6335d08b 100644 --- a/hibernate-core/src/main/java/org/hibernate/type/descriptor/jdbc/ArrayJdbcType.java +++ b/hibernate-core/src/main/java/org/hibernate/type/descriptor/jdbc/ArrayJdbcType.java @@ -214,11 +214,11 @@ public class ArrayJdbcType implements JdbcType { public boolean equals(Object o) { return o != null && getClass() == o.getClass() && - getElementJdbcType().equals( ((ArrayJdbcType) o).getElementJdbcType() ); + getElementJdbcType().equals( ( (ArrayJdbcType) o ).getElementJdbcType() ); } @Override public int hashCode() { - return getJdbcTypeCode() + getElementJdbcType().hashCode(); + return getJdbcTypeCode() + 31 * getElementJdbcType().hashCode(); } } diff --git a/hibernate-core/src/main/java/org/hibernate/type/descriptor/jdbc/spi/JdbcTypeRegistry.java b/hibernate-core/src/main/java/org/hibernate/type/descriptor/jdbc/spi/JdbcTypeRegistry.java index dfba08f3a0..cf8280bc7f 100644 --- a/hibernate-core/src/main/java/org/hibernate/type/descriptor/jdbc/spi/JdbcTypeRegistry.java +++ b/hibernate-core/src/main/java/org/hibernate/type/descriptor/jdbc/spi/JdbcTypeRegistry.java @@ -7,13 +7,20 @@ package org.hibernate.type.descriptor.jdbc.spi; import java.io.Serializable; +import java.sql.Types; import java.util.Locale; +import java.util.Objects; import java.util.concurrent.ConcurrentHashMap; +import org.hibernate.boot.model.TruthValue; +import org.hibernate.dialect.Dialect; import org.hibernate.metamodel.mapping.EmbeddableMappingType; import org.hibernate.metamodel.spi.RuntimeModelCreationContext; +import org.hibernate.tool.schema.extract.spi.ColumnTypeInformation; +import org.hibernate.type.BasicType; import org.hibernate.type.descriptor.JdbcTypeNameMapper; import org.hibernate.type.descriptor.jdbc.AggregateJdbcType; +import org.hibernate.type.descriptor.jdbc.ArrayJdbcType; import org.hibernate.type.descriptor.jdbc.JdbcType; import org.hibernate.type.descriptor.jdbc.JdbcTypeConstructor; import org.hibernate.type.descriptor.jdbc.JdbcTypeFamilyInformation; @@ -23,6 +30,8 @@ import org.hibernate.type.spi.TypeConfiguration; import org.jboss.logging.Logger; +import org.checkerframework.checker.nullness.qual.Nullable; + /** * A registry mapping {@link org.hibernate.type.SqlTypes JDBC type codes} * to implementations of the {@link JdbcType} interface. @@ -39,6 +48,13 @@ public class JdbcTypeRegistry implements JdbcTypeBaseline.BaselineTarget, Serial private final ConcurrentHashMap descriptorMap = new ConcurrentHashMap<>(); private final ConcurrentHashMap descriptorConstructorMap = new ConcurrentHashMap<>(); private final ConcurrentHashMap aggregateDescriptorMap = new ConcurrentHashMap<>(); + /** + * A registry for storing the constructed {@link JdbcType} for both + * {@link JdbcTypeConstructor#resolveType(TypeConfiguration, Dialect, JdbcType, ColumnTypeInformation)} and + * {@link JdbcTypeConstructor#resolveType(TypeConfiguration, Dialect, BasicType, ColumnTypeInformation)} in a single + * map. + */ + private final ConcurrentHashMap typeConstructorDescriptorMap = new ConcurrentHashMap<>(); public JdbcTypeRegistry(TypeConfiguration typeConfiguration) { this.typeConfiguration = typeConfiguration; @@ -174,6 +190,68 @@ public class JdbcTypeRegistry implements JdbcTypeBaseline.BaselineTarget, Serial return aggregateDescriptorMap.get( typeName.toLowerCase( Locale.ROOT ) ); } + /** + * Construct a {@link JdbcType} via {@link JdbcTypeConstructor#resolveType(TypeConfiguration, Dialect, BasicType, ColumnTypeInformation)} + * or return a compatible one from this registry. + */ + public JdbcType resolveTypeConstructorDescriptor( + int jdbcTypeConstructorCode, + BasicType elementType, + @Nullable ColumnTypeInformation columnTypeInformation) { + return resolveTypeConstructorDescriptor( jdbcTypeConstructorCode, (Object) elementType, columnTypeInformation ); + } + + /** + * Construct a {@link JdbcType} via {@link JdbcTypeConstructor#resolveType(TypeConfiguration, Dialect, JdbcType, ColumnTypeInformation)} + * or return a compatible one from this registry. + */ + public JdbcType resolveTypeConstructorDescriptor( + int jdbcTypeConstructorCode, + JdbcType elementType, + @Nullable ColumnTypeInformation columnTypeInformation) { + return resolveTypeConstructorDescriptor( jdbcTypeConstructorCode, (Object) elementType, columnTypeInformation ); + } + + private JdbcType resolveTypeConstructorDescriptor( + int jdbcTypeConstructorCode, + Object elementType, + @Nullable ColumnTypeInformation columnTypeInformation) { + final TypeConstructedJdbcTypeKey key = new TypeConstructedJdbcTypeKey( + jdbcTypeConstructorCode, + elementType, + columnTypeInformation + ); + final JdbcType descriptor = typeConstructorDescriptorMap.get( key ); + if ( descriptor != null ) { + return descriptor; + } + final JdbcTypeConstructor jdbcTypeConstructor = getConstructor( jdbcTypeConstructorCode ); + if ( jdbcTypeConstructor != null ) { + final JdbcType jdbcType; + if ( elementType instanceof BasicType ) { + jdbcType = jdbcTypeConstructor.resolveType( + typeConfiguration, + typeConfiguration.getCurrentBaseSqlTypeIndicators().getDialect(), + (BasicType) elementType, + columnTypeInformation + ); + } + else { + jdbcType = jdbcTypeConstructor.resolveType( + typeConfiguration, + typeConfiguration.getCurrentBaseSqlTypeIndicators().getDialect(), + (JdbcType) elementType, + columnTypeInformation + ); + } + final JdbcType existingType = typeConstructorDescriptorMap.putIfAbsent( key, jdbcType ); + return existingType != null ? existingType : jdbcType; + } + else { + return getDescriptor( jdbcTypeConstructorCode ); + } + } + public boolean hasRegisteredDescriptor(int jdbcTypeCode) { return descriptorMap.containsKey( jdbcTypeCode ) || JdbcTypeNameMapper.isStandardTypeCode( jdbcTypeCode ) @@ -191,4 +269,80 @@ public class JdbcTypeRegistry implements JdbcTypeBaseline.BaselineTarget, Serial public void addTypeConstructor(JdbcTypeConstructor jdbcTypeConstructor) { addTypeConstructor( jdbcTypeConstructor.getDefaultSqlTypeCode(), jdbcTypeConstructor ); } + + private static final class TypeConstructedJdbcTypeKey { + private final int typeConstructorTypeCode; + private final Object jdbcTypeOrBasicType; + private final TruthValue nullable; + private final int typeCode; + private final @Nullable String typeName; + private final int columnSize; + private final int decimalDigits; + + public TypeConstructedJdbcTypeKey( + int typeConstructorTypeCode, + Object jdbcTypeOrBasicType, + @Nullable ColumnTypeInformation columnTypeInformation) { + this.typeConstructorTypeCode = typeConstructorTypeCode; + this.jdbcTypeOrBasicType = jdbcTypeOrBasicType; + if ( columnTypeInformation == null ) { + this.nullable = TruthValue.UNKNOWN; + this.typeCode = Types.OTHER; + this.typeName = null; + this.columnSize = 0; + this.decimalDigits = 0; + } + else { + this.nullable = columnTypeInformation.getNullable(); + this.typeCode = columnTypeInformation.getTypeCode(); + this.typeName = columnTypeInformation.getTypeName(); + this.columnSize = columnTypeInformation.getColumnSize(); + this.decimalDigits = columnTypeInformation.getDecimalDigits(); + } + } + + @Override + public boolean equals(Object o) { + if ( this == o ) { + return true; + } + if ( o == null || getClass() != o.getClass() ) { + return false; + } + + TypeConstructedJdbcTypeKey that = (TypeConstructedJdbcTypeKey) o; + + if ( typeConstructorTypeCode != that.typeConstructorTypeCode ) { + return false; + } + if ( typeCode != that.typeCode ) { + return false; + } + if ( columnSize != that.columnSize ) { + return false; + } + if ( decimalDigits != that.decimalDigits ) { + return false; + } + if ( !jdbcTypeOrBasicType.equals( that.jdbcTypeOrBasicType ) ) { + return false; + } + if ( nullable != that.nullable ) { + return false; + } + return Objects.equals( typeName, that.typeName ); + } + + @Override + public int hashCode() { + int result = typeConstructorTypeCode; + result = 31 * result + jdbcTypeOrBasicType.hashCode(); + result = 31 * result + ( nullable != null ? nullable.hashCode() : 0 ); + result = 31 * result + typeCode; + result = 31 * result + ( typeName != null ? typeName.hashCode() : 0 ); + result = 31 * result + columnSize; + result = 31 * result + decimalDigits; + return result; + } + } }