HHH-16125 introduce JdbcTypeConstructor instead of using JdbcTypes as their own factories

previously, there was a global instance of ArrayJdbcType registered by the Dialects, in
an inconsistent state, that acted as a factory for correctly-initialized instances
This commit is contained in:
Gavin 2023-05-02 01:26:37 +03:00 committed by Gavin King
parent cd0504ceda
commit 473984f1eb
18 changed files with 392 additions and 201 deletions

View File

@ -72,8 +72,8 @@ import org.hibernate.sql.ast.tree.Statement;
import org.hibernate.sql.exec.spi.JdbcOperation; import org.hibernate.sql.exec.spi.JdbcOperation;
import org.hibernate.tool.schema.extract.spi.ColumnTypeInformation; import org.hibernate.tool.schema.extract.spi.ColumnTypeInformation;
import org.hibernate.type.JavaObjectType; import org.hibernate.type.JavaObjectType;
import org.hibernate.type.descriptor.jdbc.ArrayJdbcType;
import org.hibernate.type.descriptor.jdbc.JdbcType; import org.hibernate.type.descriptor.jdbc.JdbcType;
import org.hibernate.type.descriptor.jdbc.JdbcTypeConstructor;
import org.hibernate.type.descriptor.jdbc.ObjectNullAsBinaryTypeJdbcType; import org.hibernate.type.descriptor.jdbc.ObjectNullAsBinaryTypeJdbcType;
import org.hibernate.type.descriptor.jdbc.UUIDJdbcType; import org.hibernate.type.descriptor.jdbc.UUIDJdbcType;
import org.hibernate.type.descriptor.jdbc.VarbinaryJdbcType; import org.hibernate.type.descriptor.jdbc.VarbinaryJdbcType;
@ -285,13 +285,13 @@ public class CockroachLegacyDialect extends Dialect {
} }
break; break;
case ARRAY: case ARRAY:
final JdbcType jdbcType = jdbcTypeRegistry.getDescriptor( jdbcTypeCode ); final JdbcTypeConstructor jdbcTypeConstructor = jdbcTypeRegistry.getConstructor( jdbcTypeCode );
// PostgreSQL names array types by prepending an underscore to the base name // PostgreSQL names array types by prepending an underscore to the base name
if ( jdbcType instanceof ArrayJdbcType && columnTypeName.charAt( 0 ) == '_' ) { if ( jdbcTypeConstructor != null && columnTypeName.charAt( 0 ) == '_' ) {
final String componentTypeName = columnTypeName.substring( 1 ); final String componentTypeName = columnTypeName.substring( 1 );
final Integer sqlTypeCode = resolveSqlTypeCode( componentTypeName, jdbcTypeRegistry.getTypeConfiguration() ); final Integer sqlTypeCode = resolveSqlTypeCode( componentTypeName, jdbcTypeRegistry.getTypeConfiguration() );
if ( sqlTypeCode != null ) { if ( sqlTypeCode != null ) {
return ( (ArrayJdbcType) jdbcType ).resolveType( return jdbcTypeConstructor.resolveType(
jdbcTypeRegistry.getTypeConfiguration(), jdbcTypeRegistry.getTypeConfiguration(),
this, this,
jdbcTypeRegistry.getDescriptor( sqlTypeCode ), jdbcTypeRegistry.getDescriptor( sqlTypeCode ),
@ -299,7 +299,7 @@ public class CockroachLegacyDialect extends Dialect {
); );
} }
} }
return jdbcType; break;
} }
return jdbcTypeRegistry.getDescriptor( jdbcTypeCode ); return jdbcTypeRegistry.getDescriptor( jdbcTypeCode );
} }

View File

@ -793,7 +793,7 @@ public class OracleLegacyDialect extends Dialect {
} }
if ( OracleJdbcHelper.isUsable( serviceRegistry ) ) { if ( OracleJdbcHelper.isUsable( serviceRegistry ) ) {
typeContributions.contributeJdbcType( OracleJdbcHelper.getArrayJdbcType( serviceRegistry ) ); typeContributions.contributeJdbcTypeConstructor( OracleJdbcHelper.getArrayJdbcTypeConstructor( serviceRegistry ) );
} }
else { else {
typeContributions.contributeJdbcType( OracleReflectionStructJdbcType.INSTANCE ); typeContributions.contributeJdbcType( OracleReflectionStructJdbcType.INSTANCE );

View File

@ -89,10 +89,10 @@ import org.hibernate.tool.schema.extract.spi.ColumnTypeInformation;
import org.hibernate.type.JavaObjectType; import org.hibernate.type.JavaObjectType;
import org.hibernate.type.descriptor.java.PrimitiveByteArrayJavaType; import org.hibernate.type.descriptor.java.PrimitiveByteArrayJavaType;
import org.hibernate.type.descriptor.jdbc.AggregateJdbcType; import org.hibernate.type.descriptor.jdbc.AggregateJdbcType;
import org.hibernate.type.descriptor.jdbc.ArrayJdbcType;
import org.hibernate.type.descriptor.jdbc.BlobJdbcType; import org.hibernate.type.descriptor.jdbc.BlobJdbcType;
import org.hibernate.type.descriptor.jdbc.ClobJdbcType; import org.hibernate.type.descriptor.jdbc.ClobJdbcType;
import org.hibernate.type.descriptor.jdbc.JdbcType; import org.hibernate.type.descriptor.jdbc.JdbcType;
import org.hibernate.type.descriptor.jdbc.JdbcTypeConstructor;
import org.hibernate.type.descriptor.jdbc.ObjectNullAsBinaryTypeJdbcType; import org.hibernate.type.descriptor.jdbc.ObjectNullAsBinaryTypeJdbcType;
import org.hibernate.type.descriptor.jdbc.UUIDJdbcType; import org.hibernate.type.descriptor.jdbc.UUIDJdbcType;
import org.hibernate.type.descriptor.jdbc.XmlJdbcType; import org.hibernate.type.descriptor.jdbc.XmlJdbcType;
@ -337,13 +337,13 @@ public class PostgreSQLLegacyDialect extends Dialect {
} }
break; break;
case ARRAY: case ARRAY:
final JdbcType jdbcType = jdbcTypeRegistry.getDescriptor( jdbcTypeCode ); final JdbcTypeConstructor jdbcTypeConstructor = jdbcTypeRegistry.getConstructor( jdbcTypeCode );
// PostgreSQL names array types by prepending an underscore to the base name // PostgreSQL names array types by prepending an underscore to the base name
if ( jdbcType instanceof ArrayJdbcType && columnTypeName.charAt( 0 ) == '_' ) { if ( jdbcTypeConstructor != null && columnTypeName.charAt( 0 ) == '_' ) {
final String componentTypeName = columnTypeName.substring( 1 ); final String componentTypeName = columnTypeName.substring( 1 );
final Integer sqlTypeCode = resolveSqlTypeCode( componentTypeName, jdbcTypeRegistry.getTypeConfiguration() ); final Integer sqlTypeCode = resolveSqlTypeCode( componentTypeName, jdbcTypeRegistry.getTypeConfiguration() );
if ( sqlTypeCode != null ) { if ( sqlTypeCode != null ) {
return ( (ArrayJdbcType) jdbcType ).resolveType( return jdbcTypeConstructor.resolveType(
jdbcTypeRegistry.getTypeConfiguration(), jdbcTypeRegistry.getTypeConfiguration(),
this, this,
jdbcTypeRegistry.getDescriptor( sqlTypeCode ), jdbcTypeRegistry.getDescriptor( sqlTypeCode ),
@ -351,7 +351,7 @@ public class PostgreSQLLegacyDialect extends Dialect {
); );
} }
} }
return jdbcType; break;
case STRUCT: case STRUCT:
final AggregateJdbcType aggregateDescriptor = jdbcTypeRegistry.findAggregateDescriptor( columnTypeName ); final AggregateJdbcType aggregateDescriptor = jdbcTypeRegistry.findAggregateDescriptor( columnTypeName );
if ( aggregateDescriptor != null ) { if ( aggregateDescriptor != null ) {

View File

@ -13,6 +13,7 @@ import org.hibernate.type.CustomType;
import org.hibernate.type.StandardBasicTypeTemplate; import org.hibernate.type.StandardBasicTypeTemplate;
import org.hibernate.type.descriptor.java.JavaType; import org.hibernate.type.descriptor.java.JavaType;
import org.hibernate.type.descriptor.java.spi.JavaTypeRegistry; import org.hibernate.type.descriptor.java.spi.JavaTypeRegistry;
import org.hibernate.type.descriptor.jdbc.JdbcTypeConstructor;
import org.hibernate.type.descriptor.jdbc.spi.JdbcTypeRegistry; import org.hibernate.type.descriptor.jdbc.spi.JdbcTypeRegistry;
import org.hibernate.type.descriptor.jdbc.JdbcType; import org.hibernate.type.descriptor.jdbc.JdbcType;
import org.hibernate.type.spi.TypeConfiguration; import org.hibernate.type.spi.TypeConfiguration;
@ -48,6 +49,10 @@ public interface TypeContributions {
getTypeConfiguration().getJdbcTypeRegistry().addDescriptor( descriptor ); getTypeConfiguration().getJdbcTypeRegistry().addDescriptor( descriptor );
} }
default void contributeJdbcTypeConstructor(JdbcTypeConstructor typeConstructor) {
getTypeConfiguration().getJdbcTypeRegistry().addTypeConstructor( typeConstructor );
}
/** /**
* Register a {@link UserType} as the implicit (auto-applied) * Register a {@link UserType} as the implicit (auto-applied)
* type for values of type {@link UserType#returnedClass()}. * type for values of type {@link UserType#returnedClass()}.

View File

@ -59,8 +59,8 @@ import org.hibernate.sql.ast.tree.Statement;
import org.hibernate.sql.exec.spi.JdbcOperation; import org.hibernate.sql.exec.spi.JdbcOperation;
import org.hibernate.tool.schema.extract.spi.ColumnTypeInformation; import org.hibernate.tool.schema.extract.spi.ColumnTypeInformation;
import org.hibernate.type.JavaObjectType; import org.hibernate.type.JavaObjectType;
import org.hibernate.type.descriptor.jdbc.ArrayJdbcType;
import org.hibernate.type.descriptor.jdbc.JdbcType; import org.hibernate.type.descriptor.jdbc.JdbcType;
import org.hibernate.type.descriptor.jdbc.JdbcTypeConstructor;
import org.hibernate.type.descriptor.jdbc.ObjectNullAsBinaryTypeJdbcType; import org.hibernate.type.descriptor.jdbc.ObjectNullAsBinaryTypeJdbcType;
import org.hibernate.type.descriptor.jdbc.UUIDJdbcType; import org.hibernate.type.descriptor.jdbc.UUIDJdbcType;
import org.hibernate.type.descriptor.jdbc.VarbinaryJdbcType; import org.hibernate.type.descriptor.jdbc.VarbinaryJdbcType;
@ -304,13 +304,13 @@ public class CockroachDialect extends Dialect {
} }
break; break;
case ARRAY: case ARRAY:
final JdbcType jdbcType = jdbcTypeRegistry.getDescriptor( jdbcTypeCode ); final JdbcTypeConstructor jdbcTypeConstructor = jdbcTypeRegistry.getConstructor( jdbcTypeCode );
// PostgreSQL names array types by prepending an underscore to the base name // PostgreSQL names array types by prepending an underscore to the base name
if ( jdbcType instanceof ArrayJdbcType && columnTypeName.charAt( 0 ) == '_' ) { if ( jdbcTypeConstructor != null && columnTypeName.charAt( 0 ) == '_' ) {
final String componentTypeName = columnTypeName.substring( 1 ); final String componentTypeName = columnTypeName.substring( 1 );
final Integer sqlTypeCode = resolveSqlTypeCode( componentTypeName, jdbcTypeRegistry.getTypeConfiguration() ); final Integer sqlTypeCode = resolveSqlTypeCode( componentTypeName, jdbcTypeRegistry.getTypeConfiguration() );
if ( sqlTypeCode != null ) { if ( sqlTypeCode != null ) {
return ( (ArrayJdbcType) jdbcType ).resolveType( return jdbcTypeConstructor.resolveType(
jdbcTypeRegistry.getTypeConfiguration(), jdbcTypeRegistry.getTypeConfiguration(),
this, this,
jdbcTypeRegistry.getDescriptor( sqlTypeCode ), jdbcTypeRegistry.getDescriptor( sqlTypeCode ),
@ -318,7 +318,7 @@ public class CockroachDialect extends Dialect {
); );
} }
} }
return jdbcType; break;
} }
return jdbcTypeRegistry.getDescriptor( jdbcTypeCode ); return jdbcTypeRegistry.getDescriptor( jdbcTypeCode );
} }

View File

@ -175,11 +175,12 @@ import org.hibernate.type.StandardBasicTypes;
import org.hibernate.type.descriptor.WrapperOptions; import org.hibernate.type.descriptor.WrapperOptions;
import org.hibernate.type.descriptor.java.JavaType; import org.hibernate.type.descriptor.java.JavaType;
import org.hibernate.type.descriptor.java.PrimitiveByteArrayJavaType; import org.hibernate.type.descriptor.java.PrimitiveByteArrayJavaType;
import org.hibernate.type.descriptor.jdbc.ArrayJdbcType; import org.hibernate.type.descriptor.jdbc.ArrayJdbcTypeConstructor;
import org.hibernate.type.descriptor.jdbc.BlobJdbcType; import org.hibernate.type.descriptor.jdbc.BlobJdbcType;
import org.hibernate.type.descriptor.jdbc.ClobJdbcType; import org.hibernate.type.descriptor.jdbc.ClobJdbcType;
import org.hibernate.type.descriptor.jdbc.JdbcLiteralFormatter; import org.hibernate.type.descriptor.jdbc.JdbcLiteralFormatter;
import org.hibernate.type.descriptor.jdbc.JdbcType; import org.hibernate.type.descriptor.jdbc.JdbcType;
import org.hibernate.type.descriptor.jdbc.JdbcTypeConstructor;
import org.hibernate.type.descriptor.jdbc.LongNVarcharJdbcType; import org.hibernate.type.descriptor.jdbc.LongNVarcharJdbcType;
import org.hibernate.type.descriptor.jdbc.NCharJdbcType; import org.hibernate.type.descriptor.jdbc.NCharJdbcType;
import org.hibernate.type.descriptor.jdbc.NClobJdbcType; import org.hibernate.type.descriptor.jdbc.NClobJdbcType;
@ -694,25 +695,27 @@ public abstract class Dialect implements ConversionContext, TypeContributor, Fun
int precision, int precision,
int scale, int scale,
JdbcTypeRegistry jdbcTypeRegistry) { JdbcTypeRegistry jdbcTypeRegistry) {
final JdbcType jdbcType = jdbcTypeRegistry.getDescriptor( jdbcTypeCode ); if ( jdbcTypeCode == ARRAY ) {
if ( jdbcTypeCode == Types.ARRAY && jdbcType instanceof ArrayJdbcType ) { final JdbcTypeConstructor jdbcTypeConstructor = jdbcTypeRegistry.getConstructor( jdbcTypeCode );
// Special handling for array types, because we need the proper element/component type if ( jdbcTypeConstructor != null ) {
// To determine the element JdbcType, we pass the database reported type to #resolveSqlTypeCode // Special handling for array types, because we need the proper element/component type
final int arraySuffixIndex = columnTypeName.toLowerCase( Locale.ROOT ).indexOf( " array" ); // To determine the element JdbcType, we pass the database reported type to #resolveSqlTypeCode
if ( arraySuffixIndex != -1 ) { final int arraySuffixIndex = columnTypeName.toLowerCase( Locale.ROOT ).indexOf( " array" );
final String componentTypeName = columnTypeName.substring( 0, arraySuffixIndex ); if ( arraySuffixIndex != -1 ) {
final Integer sqlTypeCode = resolveSqlTypeCode( componentTypeName, jdbcTypeRegistry.getTypeConfiguration() ); final String componentTypeName = columnTypeName.substring( 0, arraySuffixIndex );
if ( sqlTypeCode != null ) { final Integer sqlTypeCode = resolveSqlTypeCode( componentTypeName, jdbcTypeRegistry.getTypeConfiguration() );
return ( (ArrayJdbcType) jdbcType ).resolveType( if ( sqlTypeCode != null ) {
jdbcTypeRegistry.getTypeConfiguration(), return jdbcTypeConstructor.resolveType(
this, jdbcTypeRegistry.getTypeConfiguration(),
jdbcTypeRegistry.getDescriptor( sqlTypeCode ), this,
ColumnTypeInformation.EMPTY jdbcTypeRegistry.getDescriptor( sqlTypeCode ),
); ColumnTypeInformation.EMPTY
);
}
} }
} }
} }
return jdbcType; return jdbcTypeRegistry.getDescriptor( jdbcTypeCode );
} }
/** /**
@ -1626,7 +1629,7 @@ public abstract class Dialect implements ConversionContext, TypeContributor, Fun
} }
if ( supportsStandardArrays() ) { if ( supportsStandardArrays() ) {
jdbcTypeRegistry.addDescriptor( ArrayJdbcType.INSTANCE ); jdbcTypeRegistry.addTypeConstructor( ArrayJdbcTypeConstructor.INSTANCE );
} }
if ( supportsMaterializedLobAccess() ) { if ( supportsMaterializedLobAccess() ) {
jdbcTypeRegistry.addDescriptor( SqlTypes.MATERIALIZED_BLOB, BlobJdbcType.MATERIALIZED ); jdbcTypeRegistry.addDescriptor( SqlTypes.MATERIALIZED_BLOB, BlobJdbcType.MATERIALIZED );

View File

@ -9,6 +9,7 @@ package org.hibernate.dialect;
import java.lang.reflect.Array; import java.lang.reflect.Array;
import java.sql.CallableStatement; import java.sql.CallableStatement;
import java.sql.PreparedStatement; import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException; import java.sql.SQLException;
import java.sql.Types; import java.sql.Types;
import java.util.Locale; import java.util.Locale;
@ -17,14 +18,13 @@ import org.hibernate.HibernateException;
import org.hibernate.boot.model.relational.Database; import org.hibernate.boot.model.relational.Database;
import org.hibernate.boot.model.relational.NamedAuxiliaryDatabaseObject; import org.hibernate.boot.model.relational.NamedAuxiliaryDatabaseObject;
import org.hibernate.engine.jdbc.Size; import org.hibernate.engine.jdbc.Size;
import org.hibernate.tool.schema.extract.spi.ColumnTypeInformation;
import org.hibernate.type.BasicType;
import org.hibernate.type.descriptor.ValueBinder; import org.hibernate.type.descriptor.ValueBinder;
import org.hibernate.type.descriptor.ValueExtractor;
import org.hibernate.type.descriptor.WrapperOptions; import org.hibernate.type.descriptor.WrapperOptions;
import org.hibernate.type.descriptor.java.BasicPluralJavaType; import org.hibernate.type.descriptor.java.BasicPluralJavaType;
import org.hibernate.type.descriptor.java.JavaType; import org.hibernate.type.descriptor.java.JavaType;
import org.hibernate.type.descriptor.jdbc.ArrayJdbcType;
import org.hibernate.type.descriptor.jdbc.BasicBinder; 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.JdbcLiteralFormatter;
import org.hibernate.type.descriptor.jdbc.JdbcType; import org.hibernate.type.descriptor.jdbc.JdbcType;
import org.hibernate.type.internal.BasicTypeImpl; import org.hibernate.type.internal.BasicTypeImpl;
@ -42,17 +42,38 @@ import static org.hibernate.internal.util.collections.ArrayHelper.EMPTY_STRING_A
* @author Christian Beikov * @author Christian Beikov
* @author Jordan Gigov * @author Jordan Gigov
*/ */
public class OracleArrayJdbcType extends ArrayJdbcType { public class OracleArrayJdbcType implements JdbcType {
private final JdbcType elementJdbcType;
private final String typeName; private final String typeName;
public OracleArrayJdbcType() { public OracleArrayJdbcType(JdbcType elementJdbcType, String typeName) {
this( null, null ); this.elementJdbcType = elementJdbcType;
this.typeName = typeName;
} }
public OracleArrayJdbcType(JdbcType elementJdbcType, String typeName) { @Override
super( elementJdbcType ); public int getJdbcTypeCode() {
this.typeName = typeName; return Types.ARRAY;
}
public JdbcType getElementJdbcType() {
return elementJdbcType;
}
@Override
public <T> JavaType<T> getJdbcRecommendedJavaTypeMapping(
Integer precision,
Integer scale,
TypeConfiguration typeConfiguration) {
final JavaType<Object> elementJavaType = elementJdbcType.getJdbcRecommendedJavaTypeMapping(
precision,
scale,
typeConfiguration
);
return typeConfiguration.getJavaTypeRegistry().resolveDescriptor(
Array.newInstance( elementJavaType.getJavaTypeClass(), 0 ).getClass()
);
} }
@Override @Override
@ -61,30 +82,8 @@ public class OracleArrayJdbcType extends ArrayJdbcType {
} }
@Override @Override
public JdbcType resolveType( public Class<?> getPreferredJavaTypeClass(WrapperOptions options) {
TypeConfiguration typeConfiguration, return java.sql.Array.class;
Dialect dialect, BasicType<?> elementType,
ColumnTypeInformation columnTypeInformation) {
String typeName = columnTypeInformation.getTypeName();
if ( typeName == null || typeName.isBlank() ) {
typeName = getTypeName( elementType.getJavaTypeDescriptor(), dialect );
}
// if ( typeName == null ) {
// // Fallback to XML type for the representation of arrays as the native JSON type was only introduced in 21
// // Also, use the XML type if the Oracle JDBC driver classes are not visible
// return typeConfiguration.getJdbcTypeRegistry().getDescriptor( SqlTypes.SQLXML );
// }
return new OracleArrayJdbcType( elementType.getJdbcType(), typeName );
}
@Override
public JdbcType resolveType(
TypeConfiguration typeConfiguration,
Dialect dialect,
JdbcType elementType,
ColumnTypeInformation columnTypeInformation) {
// a bit wrong!
return new OracleArrayJdbcType( elementType, columnTypeInformation.getTypeName() );
} }
@Override @Override
@ -146,12 +145,32 @@ public class OracleArrayJdbcType extends ArrayJdbcType {
}; };
} }
private static String getTypeName(WrapperOptions options, BasicPluralJavaType<?> containerJavaType) { @Override
public <X> ValueExtractor<X> getExtractor(final JavaType<X> javaTypeDescriptor) {
return new BasicExtractor<>( javaTypeDescriptor, this ) {
@Override
protected X doExtract(ResultSet rs, int paramIndex, WrapperOptions options) throws SQLException {
return javaTypeDescriptor.wrap( rs.getArray( paramIndex ), options );
}
@Override
protected X doExtract(CallableStatement statement, int index, WrapperOptions options) throws SQLException {
return javaTypeDescriptor.wrap( statement.getArray( index ), options );
}
@Override
protected X doExtract(CallableStatement statement, String name, WrapperOptions options) throws SQLException {
return javaTypeDescriptor.wrap( statement.getArray( name ), options );
}
};
}
static String getTypeName(WrapperOptions options, BasicPluralJavaType<?> containerJavaType) {
Dialect dialect = options.getSessionFactory().getJdbcServices().getDialect(); Dialect dialect = options.getSessionFactory().getJdbcServices().getDialect();
return getTypeName( containerJavaType.getElementJavaType(), dialect ); return getTypeName( containerJavaType.getElementJavaType(), dialect );
} }
private static String getTypeName(JavaType<?> elementJavaType, Dialect dialect) { static String getTypeName(JavaType<?> elementJavaType, Dialect dialect) {
return dialect.getArrayTypeName( return dialect.getArrayTypeName(
elementJavaType.getJavaTypeClass().getSimpleName(), elementJavaType.getJavaTypeClass().getSimpleName(),
null // not needed by OracleDialect.getArrayTypeName() null // not needed by OracleDialect.getArrayTypeName()
@ -212,4 +231,14 @@ public class OracleArrayJdbcType extends ArrayJdbcType {
// String elementTypeName = getTypeName( pluralJavaType.getElementJavaType(), dialect ); // String elementTypeName = getTypeName( pluralJavaType.getElementJavaType(), dialect );
// return " nested table " + columnName + " store as " + tableName + columnName + elementTypeName; // return " nested table " + columnName + " store as " + tableName + columnName + elementTypeName;
// } // }
@Override
public String getFriendlyName() {
return typeName;
}
@Override
public String toString() {
return "OracleArrayTypeDescriptor(" + typeName + ")";
}
} }

View File

@ -0,0 +1,56 @@
/*
* 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.dialect;
import org.hibernate.tool.schema.extract.spi.ColumnTypeInformation;
import org.hibernate.type.BasicType;
import org.hibernate.type.descriptor.jdbc.JdbcType;
import org.hibernate.type.descriptor.jdbc.JdbcTypeConstructor;
import org.hibernate.type.spi.TypeConfiguration;
import java.sql.Types;
/**
* Factory for {@link OracleArrayJdbcType}.
*
* @see OracleJdbcHelper#getArrayJdbcTypeConstructor
*
* @author Gavin King
*/
public class OracleArrayJdbcTypeConstructor implements JdbcTypeConstructor {
@Override
public JdbcType resolveType(
TypeConfiguration typeConfiguration,
Dialect dialect, BasicType<?> elementType,
ColumnTypeInformation columnTypeInformation) {
String typeName = columnTypeInformation.getTypeName();
if ( typeName == null || typeName.isBlank() ) {
typeName = OracleArrayJdbcType.getTypeName( elementType.getJavaTypeDescriptor(), dialect );
}
// if ( typeName == null ) {
// // Fallback to XML type for the representation of arrays as the native JSON type was only introduced in 21
// // Also, use the XML type if the Oracle JDBC driver classes are not visible
// return typeConfiguration.getJdbcTypeRegistry().getDescriptor( SqlTypes.SQLXML );
// }
return new OracleArrayJdbcType( elementType.getJdbcType(), typeName );
}
@Override
public JdbcType resolveType(
TypeConfiguration typeConfiguration,
Dialect dialect,
JdbcType elementType,
ColumnTypeInformation columnTypeInformation) {
// a bit wrong, since columnTypeInformation.getTypeName() is typically null!
return new OracleArrayJdbcType( elementType, columnTypeInformation.getTypeName() );
}
@Override
public int getDefaultSqlTypeCode() {
return Types.ARRAY;
}
}

View File

@ -99,6 +99,7 @@ import static org.hibernate.LockOptions.NO_WAIT;
import static org.hibernate.LockOptions.SKIP_LOCKED; import static org.hibernate.LockOptions.SKIP_LOCKED;
import static org.hibernate.LockOptions.WAIT_FOREVER; import static org.hibernate.LockOptions.WAIT_FOREVER;
import static org.hibernate.cfg.AvailableSettings.BATCH_VERSIONED_DATA; import static org.hibernate.cfg.AvailableSettings.BATCH_VERSIONED_DATA;
import static org.hibernate.dialect.OracleJdbcHelper.getArrayJdbcTypeConstructor;
import static org.hibernate.exception.spi.TemplatedViolatedConstraintNameExtractor.extractUsingTemplate; import static org.hibernate.exception.spi.TemplatedViolatedConstraintNameExtractor.extractUsingTemplate;
import static org.hibernate.internal.util.StringHelper.isEmpty; import static org.hibernate.internal.util.StringHelper.isEmpty;
import static org.hibernate.query.sqm.TemporalUnit.DAY; import static org.hibernate.query.sqm.TemporalUnit.DAY;
@ -831,7 +832,7 @@ public class OracleDialect extends Dialect {
} }
if ( OracleJdbcHelper.isUsable( serviceRegistry ) ) { if ( OracleJdbcHelper.isUsable( serviceRegistry ) ) {
typeContributions.contributeJdbcType( OracleJdbcHelper.getArrayJdbcType( serviceRegistry ) ); typeContributions.contributeJdbcTypeConstructor( getArrayJdbcTypeConstructor( serviceRegistry ) );
} }
else { else {
typeContributions.contributeJdbcType( OracleReflectionStructJdbcType.INSTANCE ); typeContributions.contributeJdbcType( OracleReflectionStructJdbcType.INSTANCE );

View File

@ -6,7 +6,6 @@
*/ */
package org.hibernate.dialect; package org.hibernate.dialect;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException; import java.lang.reflect.InvocationTargetException;
import org.hibernate.HibernateError; import org.hibernate.HibernateError;
@ -14,6 +13,7 @@ import org.hibernate.boot.registry.classloading.spi.ClassLoaderService;
import org.hibernate.boot.registry.classloading.spi.ClassLoadingException; import org.hibernate.boot.registry.classloading.spi.ClassLoadingException;
import org.hibernate.service.ServiceRegistry; import org.hibernate.service.ServiceRegistry;
import org.hibernate.type.descriptor.jdbc.JdbcType; import org.hibernate.type.descriptor.jdbc.JdbcType;
import org.hibernate.type.descriptor.jdbc.JdbcTypeConstructor;
/** /**
* The following class provides some convenience methods for accessing JdbcType instance, * The following class provides some convenience methods for accessing JdbcType instance,
@ -34,20 +34,18 @@ public class OracleJdbcHelper {
} }
} }
public static JdbcType getArrayJdbcType(ServiceRegistry serviceRegistry) { public static JdbcTypeConstructor getArrayJdbcTypeConstructor(ServiceRegistry serviceRegistry) {
return createJdbcType( serviceRegistry, "org.hibernate.dialect.OracleArrayJdbcType" ); return create( serviceRegistry, "org.hibernate.dialect.OracleArrayJdbcTypeConstructor" );
} }
public static JdbcType getStructJdbcType(ServiceRegistry serviceRegistry) { public static JdbcType getStructJdbcType(ServiceRegistry serviceRegistry) {
return createJdbcType( serviceRegistry, "org.hibernate.dialect.OracleStructJdbcType" ); return create( serviceRegistry, "org.hibernate.dialect.OracleStructJdbcType" );
} }
public static JdbcType createJdbcType(ServiceRegistry serviceRegistry, String className) { public static <X> X create(ServiceRegistry serviceRegistry, String className) {
final ClassLoaderService classLoaderService = serviceRegistry.getService( ClassLoaderService.class ); final ClassLoaderService classLoaderService = serviceRegistry.getService( ClassLoaderService.class );
try { try {
final Class<?> clazz = classLoaderService.classForName( className ); return classLoaderService.<X>classForName( className ).getConstructor().newInstance();
final Constructor<?> constructor = clazz.getConstructor();
return (JdbcType) constructor.newInstance();
} }
catch (NoSuchMethodException e) { catch (NoSuchMethodException e) {
throw new HibernateError( "Class does not have an empty constructor", e ); throw new HibernateError( "Class does not have an empty constructor", e );

View File

@ -82,6 +82,7 @@ import org.hibernate.type.descriptor.jdbc.ArrayJdbcType;
import org.hibernate.type.descriptor.jdbc.BlobJdbcType; import org.hibernate.type.descriptor.jdbc.BlobJdbcType;
import org.hibernate.type.descriptor.jdbc.ClobJdbcType; import org.hibernate.type.descriptor.jdbc.ClobJdbcType;
import org.hibernate.type.descriptor.jdbc.JdbcType; import org.hibernate.type.descriptor.jdbc.JdbcType;
import org.hibernate.type.descriptor.jdbc.JdbcTypeConstructor;
import org.hibernate.type.descriptor.jdbc.ObjectNullAsBinaryTypeJdbcType; import org.hibernate.type.descriptor.jdbc.ObjectNullAsBinaryTypeJdbcType;
import org.hibernate.type.descriptor.jdbc.UUIDJdbcType; import org.hibernate.type.descriptor.jdbc.UUIDJdbcType;
import org.hibernate.type.descriptor.jdbc.XmlJdbcType; import org.hibernate.type.descriptor.jdbc.XmlJdbcType;
@ -316,13 +317,13 @@ public class PostgreSQLDialect extends Dialect {
} }
break; break;
case ARRAY: case ARRAY:
final JdbcType jdbcType = jdbcTypeRegistry.getDescriptor( jdbcTypeCode ); final JdbcTypeConstructor jdbcTypeConstructor = jdbcTypeRegistry.getConstructor( jdbcTypeCode );
// PostgreSQL names array types by prepending an underscore to the base name // PostgreSQL names array types by prepending an underscore to the base name
if ( jdbcType instanceof ArrayJdbcType && columnTypeName.charAt( 0 ) == '_' ) { if ( jdbcTypeConstructor != null && columnTypeName.charAt( 0 ) == '_' ) {
final String componentTypeName = columnTypeName.substring( 1 ); final String componentTypeName = columnTypeName.substring( 1 );
final Integer sqlTypeCode = resolveSqlTypeCode( componentTypeName, jdbcTypeRegistry.getTypeConfiguration() ); final Integer sqlTypeCode = resolveSqlTypeCode( componentTypeName, jdbcTypeRegistry.getTypeConfiguration() );
if ( sqlTypeCode != null ) { if ( sqlTypeCode != null ) {
return ( (ArrayJdbcType) jdbcType ).resolveType( return jdbcTypeConstructor.resolveType(
jdbcTypeRegistry.getTypeConfiguration(), jdbcTypeRegistry.getTypeConfiguration(),
this, this,
jdbcTypeRegistry.getDescriptor( sqlTypeCode ), jdbcTypeRegistry.getDescriptor( sqlTypeCode ),
@ -330,7 +331,7 @@ public class PostgreSQLDialect extends Dialect {
); );
} }
} }
return jdbcType; break;
case STRUCT: case STRUCT:
final AggregateJdbcType aggregateDescriptor = jdbcTypeRegistry.findAggregateDescriptor( columnTypeName ); final AggregateJdbcType aggregateDescriptor = jdbcTypeRegistry.findAggregateDescriptor( columnTypeName );
if ( aggregateDescriptor != null ) { if ( aggregateDescriptor != null ) {

View File

@ -18,9 +18,10 @@ import org.hibernate.type.BasicPluralType;
import org.hibernate.type.BasicType; import org.hibernate.type.BasicType;
import org.hibernate.type.ConvertedBasicArrayType; import org.hibernate.type.ConvertedBasicArrayType;
import org.hibernate.type.descriptor.converter.spi.BasicValueConverter; import org.hibernate.type.descriptor.converter.spi.BasicValueConverter;
import org.hibernate.type.descriptor.jdbc.ArrayJdbcType;
import org.hibernate.type.descriptor.jdbc.JdbcType; 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.JdbcTypeIndicators;
import org.hibernate.type.descriptor.jdbc.spi.JdbcTypeRegistry;
import org.hibernate.type.internal.BasicTypeImpl; import org.hibernate.type.internal.BasicTypeImpl;
import org.hibernate.type.spi.TypeConfiguration; import org.hibernate.type.spi.TypeConfiguration;
@ -45,20 +46,14 @@ public abstract class AbstractArrayJavaType<T, E> extends AbstractClassJavaType<
@Override @Override
public JdbcType getRecommendedJdbcType(JdbcTypeIndicators indicators) { public JdbcType getRecommendedJdbcType(JdbcTypeIndicators indicators) {
final int preferredSqlTypeCodeForArray = indicators.getPreferredSqlTypeCodeForArray();
// Always determine the recommended type to make sure this is a valid basic java type // Always determine the recommended type to make sure this is a valid basic java type
final JdbcType recommendedComponentJdbcType = componentJavaType.getRecommendedJdbcType( indicators ); return getArrayJdbcType(
final TypeConfiguration typeConfiguration = indicators.getTypeConfiguration(); indicators.getTypeConfiguration(),
final JdbcType jdbcType = typeConfiguration.getJdbcTypeRegistry().getDescriptor( preferredSqlTypeCodeForArray ); indicators.getDialect(),
if ( jdbcType instanceof ArrayJdbcType ) { indicators.getPreferredSqlTypeCodeForArray(),
return ( (ArrayJdbcType) jdbcType ).resolveType( new BasicTypeImpl<>( getElementJavaType(), componentJavaType.getRecommendedJdbcType( indicators ) ),
typeConfiguration, ColumnTypeInformation.EMPTY
indicators.getDialect(), );
new BasicTypeImpl<>( getElementJavaType(), recommendedComponentJdbcType ),
ColumnTypeInformation.EMPTY
);
}
return jdbcType;
} }
@Override @Override
@ -75,44 +70,51 @@ public abstract class AbstractArrayJavaType<T, E> extends AbstractClassJavaType<
final BasicValueConverter<E, ?> valueConverter = elementType.getValueConverter(); final BasicValueConverter<E, ?> valueConverter = elementType.getValueConverter();
if ( valueConverter == null ) { if ( valueConverter == null ) {
final Function<JavaType<T>, BasicType<T>> creator = javaType -> { final Function<JavaType<T>, BasicType<T>> creator = javaType -> {
JdbcType arrayJdbcType = typeConfiguration.getJdbcTypeRegistry().getDescriptor( Types.ARRAY ); final JdbcType arrayJdbcType =
if ( arrayJdbcType instanceof ArrayJdbcType ) { getArrayJdbcType( typeConfiguration, dialect, Types.ARRAY, elementType, columnTypeInformation );
arrayJdbcType = ( (ArrayJdbcType) arrayJdbcType ).resolveType(
typeConfiguration,
dialect,
elementType,
columnTypeInformation
);
}
//noinspection unchecked,rawtypes //noinspection unchecked,rawtypes
return new BasicArrayType( elementType, arrayJdbcType, javaType ); return new BasicArrayType( elementType, arrayJdbcType, javaType );
}; };
if ( typeConfiguration.getBasicTypeRegistry().getRegisteredType( elementType.getName() ) == elementType ) { if ( typeConfiguration.getBasicTypeRegistry().getRegisteredType( elementType.getName() ) == elementType ) {
return typeConfiguration.standardBasicTypeForJavaType( getJavaType(), creator ); return typeConfiguration.standardBasicTypeForJavaType( getJavaType(), creator );
} }
return creator.apply( this ); else {
return creator.apply( this );
}
} }
else { else {
final JavaType<Object> relationalJavaType = typeConfiguration.getJavaTypeRegistry().getDescriptor( final JavaType<Object> relationalJavaType = typeConfiguration.getJavaTypeRegistry().getDescriptor(
Array.newInstance( valueConverter.getRelationalJavaType().getJavaTypeClass(), 0 ).getClass() Array.newInstance( valueConverter.getRelationalJavaType().getJavaTypeClass(), 0 ).getClass()
); );
JdbcType arrayJdbcType = typeConfiguration.getJdbcTypeRegistry().getDescriptor( Types.ARRAY );
if ( arrayJdbcType instanceof ArrayJdbcType ) {
arrayJdbcType = ( (ArrayJdbcType) arrayJdbcType ).resolveType(
typeConfiguration,
dialect,
elementType,
columnTypeInformation
);
}
//noinspection unchecked,rawtypes //noinspection unchecked,rawtypes
return new ConvertedBasicArrayType( return new ConvertedBasicArrayType(
elementType, elementType,
arrayJdbcType, getArrayJdbcType( typeConfiguration, dialect, Types.ARRAY, elementType, columnTypeInformation ),
this, this,
new ArrayConverter( valueConverter, this, relationalJavaType ) new ArrayConverter( valueConverter, this, relationalJavaType )
); );
} }
} }
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 );
}
}
} }

View File

@ -26,9 +26,10 @@ import org.hibernate.type.BasicType;
import org.hibernate.type.ConvertedBasicArrayType; import org.hibernate.type.ConvertedBasicArrayType;
import org.hibernate.type.descriptor.WrapperOptions; import org.hibernate.type.descriptor.WrapperOptions;
import org.hibernate.type.descriptor.converter.spi.BasicValueConverter; import org.hibernate.type.descriptor.converter.spi.BasicValueConverter;
import org.hibernate.type.descriptor.jdbc.ArrayJdbcType;
import org.hibernate.type.descriptor.jdbc.JdbcType; 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.JdbcTypeIndicators;
import org.hibernate.type.descriptor.jdbc.spi.JdbcTypeRegistry;
import org.hibernate.type.spi.TypeConfiguration; import org.hibernate.type.spi.TypeConfiguration;
/** /**
@ -86,19 +87,11 @@ public class ArrayJavaType<T> extends AbstractArrayJavaType<T[], T> {
// Register the array type as that will be resolved in the next step // Register the array type as that will be resolved in the next step
typeConfiguration.getJavaTypeRegistry().addDescriptor( arrayJavaType ); typeConfiguration.getJavaTypeRegistry().addDescriptor( arrayJavaType );
} }
//noinspection unchecked final BasicValueConverter<T, ?> valueConverter = elementType.getValueConverter();
final BasicValueConverter<Object, Object> valueConverter = (BasicValueConverter<Object, Object>) elementType.getValueConverter();
if ( valueConverter == null ) { if ( valueConverter == null ) {
final Function<JavaType<T[]>, BasicType<T[]>> creator = javaType -> { final Function<JavaType<T[]>, BasicType<T[]>> creator = javaType -> {
JdbcType arrayJdbcType = typeConfiguration.getJdbcTypeRegistry().getDescriptor( Types.ARRAY ); final JdbcType arrayJdbcType =
if ( arrayJdbcType instanceof ArrayJdbcType ) { getArrayJdbcType( typeConfiguration, dialect, Types.ARRAY, elementType, columnTypeInformation );
arrayJdbcType = ( (ArrayJdbcType) arrayJdbcType ).resolveType(
typeConfiguration,
dialect,
elementType,
columnTypeInformation
);
}
return new BasicArrayType<>( elementType, arrayJdbcType, javaType ); return new BasicArrayType<>( elementType, arrayJdbcType, javaType );
}; };
if ( typeConfiguration.getBasicTypeRegistry().getRegisteredType( elementType.getName() ) == elementType ) { if ( typeConfiguration.getBasicTypeRegistry().getRegisteredType( elementType.getName() ) == elementType ) {
@ -110,26 +103,39 @@ public class ArrayJavaType<T> extends AbstractArrayJavaType<T[], T> {
final JavaType<Object> relationalJavaType = typeConfiguration.getJavaTypeRegistry().getDescriptor( final JavaType<Object> relationalJavaType = typeConfiguration.getJavaTypeRegistry().getDescriptor(
Array.newInstance( valueConverter.getRelationalJavaType().getJavaTypeClass(), 0 ).getClass() Array.newInstance( valueConverter.getRelationalJavaType().getJavaTypeClass(), 0 ).getClass()
); );
//noinspection unchecked,rawtypes
JdbcType arrayJdbcType = typeConfiguration.getJdbcTypeRegistry().getDescriptor( Types.ARRAY ); return new ConvertedBasicArrayType(
if ( arrayJdbcType instanceof ArrayJdbcType ) {
arrayJdbcType = ( (ArrayJdbcType) arrayJdbcType ).resolveType(
typeConfiguration,
dialect,
elementType,
columnTypeInformation
);
}
//noinspection unchecked
return new ConvertedBasicArrayType<>(
elementType, elementType,
arrayJdbcType, getArrayJdbcType( typeConfiguration, dialect, Types.ARRAY, elementType, columnTypeInformation ),
arrayJavaType, arrayJavaType,
new ArrayConverter<>( valueConverter, arrayJavaType, relationalJavaType ) new ArrayConverter( valueConverter, arrayJavaType, relationalJavaType )
); );
} }
} }
//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 @Override
public String extractLoggableRepresentation(T[] value) { public String extractLoggableRepresentation(T[] value) {
if ( value == null ) { if ( value == null ) {

View File

@ -38,9 +38,11 @@ import org.hibernate.type.descriptor.java.AbstractJavaType;
import org.hibernate.type.descriptor.java.BasicPluralJavaType; import org.hibernate.type.descriptor.java.BasicPluralJavaType;
import org.hibernate.type.descriptor.java.JavaType; import org.hibernate.type.descriptor.java.JavaType;
import org.hibernate.type.descriptor.java.MutabilityPlan; import org.hibernate.type.descriptor.java.MutabilityPlan;
import org.hibernate.type.descriptor.jdbc.ArrayJdbcType;
import org.hibernate.type.descriptor.jdbc.JdbcType; 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.JdbcTypeIndicators;
import org.hibernate.type.descriptor.jdbc.spi.JdbcTypeRegistry;
import org.hibernate.type.internal.BasicTypeImpl;
import org.hibernate.type.spi.TypeConfiguration; import org.hibernate.type.spi.TypeConfiguration;
/** /**
@ -68,21 +70,15 @@ public class BasicCollectionJavaType<C extends Collection<E>, E> extends Abstrac
@Override @Override
public JdbcType getRecommendedJdbcType(JdbcTypeIndicators indicators) { public JdbcType getRecommendedJdbcType(JdbcTypeIndicators indicators) {
final int preferredSqlTypeCodeForArray = indicators.getPreferredSqlTypeCodeForArray();
// Always determine the recommended type to make sure this is a valid basic java type // 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) // (even though we only use this inside the if block, we want it to throw here if something wrong)
final JdbcType recommendedComponentJdbcType = componentJavaType.getRecommendedJdbcType( indicators ); return getArrayJdbcType(
final JdbcType jdbcType = indicators.getJdbcType( preferredSqlTypeCodeForArray ); indicators.getTypeConfiguration(),
if ( jdbcType instanceof ArrayJdbcType ) { indicators.getDialect(),
final TypeConfiguration typeConfiguration = indicators.getTypeConfiguration(); indicators.getPreferredSqlTypeCodeForArray(),
return ( (ArrayJdbcType) jdbcType ).resolveType( new BasicTypeImpl<>( getElementJavaType(), componentJavaType.getRecommendedJdbcType( indicators ) ),
typeConfiguration, ColumnTypeInformation.EMPTY
indicators.getDialect(), );
recommendedComponentJdbcType,
ColumnTypeInformation.EMPTY
);
}
return jdbcType;
} }
public CollectionSemantics<C, E> getSemantics() { public CollectionSemantics<C, E> getSemantics() {
@ -117,15 +113,8 @@ public class BasicCollectionJavaType<C extends Collection<E>, E> extends Abstrac
final BasicValueConverter<E, ?> valueConverter = elementType.getValueConverter(); final BasicValueConverter<E, ?> valueConverter = elementType.getValueConverter();
if ( valueConverter == null ) { if ( valueConverter == null ) {
final Function<JavaType<Object>, BasicType<Object>> creator = javaType -> { final Function<JavaType<Object>, BasicType<Object>> creator = javaType -> {
JdbcType arrayJdbcType = typeConfiguration.getJdbcTypeRegistry().getDescriptor( Types.ARRAY ); final JdbcType arrayJdbcType =
if ( arrayJdbcType instanceof ArrayJdbcType ) { getArrayJdbcType( typeConfiguration, dialect, Types.ARRAY, elementType, columnTypeInformation );
arrayJdbcType = ( (ArrayJdbcType) arrayJdbcType ).resolveType(
typeConfiguration,
dialect,
elementType,
columnTypeInformation
);
}
//noinspection unchecked,rawtypes //noinspection unchecked,rawtypes
return new BasicCollectionType( elementType, arrayJdbcType, collectionJavaType ); return new BasicCollectionType( elementType, arrayJdbcType, collectionJavaType );
}; };
@ -139,26 +128,39 @@ public class BasicCollectionJavaType<C extends Collection<E>, E> extends Abstrac
final JavaType<Object> relationalJavaType = typeConfiguration.getJavaTypeRegistry().resolveDescriptor( final JavaType<Object> relationalJavaType = typeConfiguration.getJavaTypeRegistry().resolveDescriptor(
Array.newInstance( valueConverter.getRelationalJavaType().getJavaTypeClass(), 0 ).getClass() Array.newInstance( valueConverter.getRelationalJavaType().getJavaTypeClass(), 0 ).getClass()
); );
JdbcType arrayJdbcType = typeConfiguration.getJdbcTypeRegistry().getDescriptor( Types.ARRAY );
if ( arrayJdbcType instanceof ArrayJdbcType ) {
arrayJdbcType = ( (ArrayJdbcType) arrayJdbcType ).resolveType(
typeConfiguration,
dialect,
elementType,
columnTypeInformation
);
}
//noinspection unchecked,rawtypes //noinspection unchecked,rawtypes
return new ConvertedBasicCollectionType<>( return new ConvertedBasicCollectionType(
elementType, elementType,
arrayJdbcType, getArrayJdbcType( typeConfiguration, dialect, Types.ARRAY, elementType, columnTypeInformation ),
collectionJavaType, collectionJavaType,
new CollectionConverter( valueConverter, collectionJavaType, relationalJavaType ) new CollectionConverter( valueConverter, collectionJavaType, relationalJavaType )
); );
} }
} }
//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 @Override
public String extractLoggableRepresentation(C value) { public String extractLoggableRepresentation(C value) {
if ( value == null ) { if ( value == null ) {

View File

@ -14,11 +14,8 @@ import java.sql.SQLException;
import java.sql.Types; import java.sql.Types;
import org.hibernate.HibernateException; import org.hibernate.HibernateException;
import org.hibernate.dialect.Dialect;
import org.hibernate.engine.jdbc.Size; import org.hibernate.engine.jdbc.Size;
import org.hibernate.engine.spi.SharedSessionContractImplementor; import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.tool.schema.extract.spi.ColumnTypeInformation;
import org.hibernate.type.BasicType;
import org.hibernate.type.descriptor.ValueBinder; import org.hibernate.type.descriptor.ValueBinder;
import org.hibernate.type.descriptor.ValueExtractor; import org.hibernate.type.descriptor.ValueExtractor;
import org.hibernate.type.descriptor.WrapperOptions; import org.hibernate.type.descriptor.WrapperOptions;
@ -39,30 +36,12 @@ import org.hibernate.type.spi.TypeConfiguration;
*/ */
public class ArrayJdbcType implements JdbcType { public class ArrayJdbcType implements JdbcType {
public static final ArrayJdbcType INSTANCE = new ArrayJdbcType( ObjectJdbcType.INSTANCE );
private final JdbcType elementJdbcType; private final JdbcType elementJdbcType;
public ArrayJdbcType(JdbcType elementJdbcType) { public ArrayJdbcType(JdbcType elementJdbcType) {
this.elementJdbcType = elementJdbcType; this.elementJdbcType = elementJdbcType;
} }
public JdbcType resolveType(
TypeConfiguration typeConfiguration,
Dialect dialect,
BasicType<?> elementType,
ColumnTypeInformation columnTypeInformation) {
return resolveType( typeConfiguration, dialect, elementType.getJdbcType(), columnTypeInformation );
}
public JdbcType resolveType(
TypeConfiguration typeConfiguration,
Dialect dialect,
JdbcType elementType,
ColumnTypeInformation columnTypeInformation) {
return new ArrayJdbcType( elementType );
}
@Override @Override
public int getJdbcTypeCode() { public int getJdbcTypeCode() {
return Types.ARRAY; return Types.ARRAY;
@ -219,6 +198,6 @@ public class ArrayJdbcType implements JdbcType {
@Override @Override
public String toString() { public String toString() {
return "ArrayTypeDescriptor(" + getFriendlyName() + ")"; return "ArrayTypeDescriptor";
} }
} }

View File

@ -0,0 +1,44 @@
/*
* 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.jdbc;
import org.hibernate.dialect.Dialect;
import org.hibernate.tool.schema.extract.spi.ColumnTypeInformation;
import org.hibernate.type.BasicType;
import org.hibernate.type.spi.TypeConfiguration;
import java.sql.Types;
/**
* Factory for {@link ArrayJdbcType}.
*
* @author Gavin King
*/
public class ArrayJdbcTypeConstructor implements JdbcTypeConstructor {
public static final ArrayJdbcTypeConstructor INSTANCE = new ArrayJdbcTypeConstructor();
public JdbcType resolveType(
TypeConfiguration typeConfiguration,
Dialect dialect,
BasicType<?> elementType,
ColumnTypeInformation columnTypeInformation) {
return resolveType( typeConfiguration, dialect, elementType.getJdbcType(), columnTypeInformation );
}
public JdbcType resolveType(
TypeConfiguration typeConfiguration,
Dialect dialect,
JdbcType elementType,
ColumnTypeInformation columnTypeInformation) {
return new ArrayJdbcType( elementType );
}
@Override
public int getDefaultSqlTypeCode() {
return Types.ARRAY;
}
}

View File

@ -0,0 +1,50 @@
/*
* 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.jdbc;
import org.hibernate.dialect.Dialect;
import org.hibernate.tool.schema.extract.spi.ColumnTypeInformation;
import org.hibernate.type.BasicType;
import org.hibernate.type.spi.TypeConfiguration;
/**
* Factory for any {@link JdbcType} which is parameterized by
* a second {@code JdbcType}, the "element" type.
* <p>
* For example, {@link ArrayJdbcType} is parameterized by the
* type of its elements.
*
* @author Gavin King
*/
public interface JdbcTypeConstructor {
/**
* Called by {@link org.hibernate.type.descriptor.java.ArrayJavaType}
* and friends. Here we already know the type argument, which
* we're given as a {@link BasicType}.
*/
default JdbcType resolveType(
TypeConfiguration typeConfiguration,
Dialect dialect,
BasicType<?> elementType,
ColumnTypeInformation columnTypeInformation) {
return resolveType( typeConfiguration, dialect, elementType.getJdbcType(), columnTypeInformation );
}
/**
* Called from {@link Dialect#resolveSqlTypeDescriptor} when
* inferring {@link JdbcType}s from a JDBC {@code ResultSet}
* or when reverse-engineering a schema. Here we do not have
* a known {@link BasicType}.
*/
JdbcType resolveType(
TypeConfiguration typeConfiguration,
Dialect dialect,
JdbcType elementType,
ColumnTypeInformation columnTypeInformation);
int getDefaultSqlTypeCode();
}

View File

@ -15,6 +15,7 @@ import org.hibernate.metamodel.spi.RuntimeModelCreationContext;
import org.hibernate.type.descriptor.JdbcTypeNameMapper; import org.hibernate.type.descriptor.JdbcTypeNameMapper;
import org.hibernate.type.descriptor.jdbc.AggregateJdbcType; import org.hibernate.type.descriptor.jdbc.AggregateJdbcType;
import org.hibernate.type.descriptor.jdbc.JdbcType; import org.hibernate.type.descriptor.jdbc.JdbcType;
import org.hibernate.type.descriptor.jdbc.JdbcTypeConstructor;
import org.hibernate.type.descriptor.jdbc.JdbcTypeFamilyInformation; import org.hibernate.type.descriptor.jdbc.JdbcTypeFamilyInformation;
import org.hibernate.type.descriptor.jdbc.ObjectJdbcType; import org.hibernate.type.descriptor.jdbc.ObjectJdbcType;
import org.hibernate.type.descriptor.jdbc.internal.JdbcTypeBaseline; import org.hibernate.type.descriptor.jdbc.internal.JdbcTypeBaseline;
@ -36,6 +37,7 @@ public class JdbcTypeRegistry implements JdbcTypeBaseline.BaselineTarget, Serial
private final TypeConfiguration typeConfiguration; private final TypeConfiguration typeConfiguration;
private final ConcurrentHashMap<Integer, JdbcType> descriptorMap = new ConcurrentHashMap<>(); private final ConcurrentHashMap<Integer, JdbcType> descriptorMap = new ConcurrentHashMap<>();
private final ConcurrentHashMap<Integer, JdbcTypeConstructor> descriptorConstructorMap = new ConcurrentHashMap<>();
private final ConcurrentHashMap<String, AggregateJdbcType> aggregateDescriptorMap = new ConcurrentHashMap<>(); private final ConcurrentHashMap<String, AggregateJdbcType> aggregateDescriptorMap = new ConcurrentHashMap<>();
public JdbcTypeRegistry(TypeConfiguration typeConfiguration) { public JdbcTypeRegistry(TypeConfiguration typeConfiguration) {
@ -91,7 +93,8 @@ public class JdbcTypeRegistry implements JdbcTypeBaseline.BaselineTarget, Serial
} }
// see if the typecode is part of a known type family... // see if the typecode is part of a known type family...
JdbcTypeFamilyInformation.Family family = JdbcTypeFamilyInformation.INSTANCE.locateJdbcTypeFamilyByTypeCode( jdbcTypeCode ); JdbcTypeFamilyInformation.Family family =
JdbcTypeFamilyInformation.INSTANCE.locateJdbcTypeFamilyByTypeCode( jdbcTypeCode );
if ( family != null ) { if ( family != null ) {
for ( int potentialAlternateTypeCode : family.getTypeCodes() ) { for ( int potentialAlternateTypeCode : family.getTypeCodes() ) {
if ( potentialAlternateTypeCode != jdbcTypeCode ) { if ( potentialAlternateTypeCode != jdbcTypeCode ) {
@ -176,4 +179,16 @@ public class JdbcTypeRegistry implements JdbcTypeBaseline.BaselineTarget, Serial
|| JdbcTypeNameMapper.isStandardTypeCode( jdbcTypeCode ) || JdbcTypeNameMapper.isStandardTypeCode( jdbcTypeCode )
|| JdbcTypeFamilyInformation.INSTANCE.locateJdbcTypeFamilyByTypeCode( jdbcTypeCode ) != null; || JdbcTypeFamilyInformation.INSTANCE.locateJdbcTypeFamilyByTypeCode( jdbcTypeCode ) != null;
} }
public JdbcTypeConstructor getConstructor(int jdbcTypeCode) {
return descriptorConstructorMap.get( jdbcTypeCode );
}
public void addTypeConstructor(int jdbcTypeCode, JdbcTypeConstructor jdbcTypeConstructor) {
descriptorConstructorMap.put( jdbcTypeCode, jdbcTypeConstructor );
}
public void addTypeConstructor(JdbcTypeConstructor jdbcTypeConstructor) {
addTypeConstructor( jdbcTypeConstructor.getDefaultSqlTypeCode(), jdbcTypeConstructor );
}
} }