HHH-16333 Handle converters properly in BasicPluralType
This commit is contained in:
parent
f68ea21891
commit
c54e156c14
|
@ -65,7 +65,7 @@ import org.hibernate.type.BasicTypeRegistry;
|
|||
import org.hibernate.type.StandardBasicTypes;
|
||||
import org.hibernate.type.descriptor.java.PrimitiveByteArrayJavaType;
|
||||
import org.hibernate.type.descriptor.jdbc.JdbcType;
|
||||
import org.hibernate.type.descriptor.jdbc.SmallIntJdbcType;
|
||||
import org.hibernate.type.descriptor.jdbc.TinyIntAsSmallIntJdbcType;
|
||||
import org.hibernate.type.descriptor.jdbc.UUIDJdbcType;
|
||||
import org.hibernate.type.descriptor.jdbc.XmlJdbcType;
|
||||
import org.hibernate.type.descriptor.jdbc.spi.JdbcTypeRegistry;
|
||||
|
@ -268,7 +268,7 @@ public class SQLServerLegacyDialect extends AbstractTransactSQLDialect {
|
|||
|
||||
typeContributions.getTypeConfiguration().getJdbcTypeRegistry().addDescriptor(
|
||||
Types.TINYINT,
|
||||
SmallIntJdbcType.INSTANCE
|
||||
TinyIntAsSmallIntJdbcType.INSTANCE
|
||||
);
|
||||
typeContributions.contributeJdbcType( XmlJdbcType.INSTANCE );
|
||||
typeContributions.contributeJdbcType( UUIDJdbcType.INSTANCE );
|
||||
|
|
|
@ -56,7 +56,7 @@ import org.hibernate.type.descriptor.jdbc.BlobJdbcType;
|
|||
import org.hibernate.type.descriptor.jdbc.ClobJdbcType;
|
||||
import org.hibernate.type.descriptor.jdbc.JdbcType;
|
||||
import org.hibernate.type.descriptor.jdbc.ObjectNullAsNullTypeJdbcType;
|
||||
import org.hibernate.type.descriptor.jdbc.SmallIntJdbcType;
|
||||
import org.hibernate.type.descriptor.jdbc.TinyIntAsSmallIntJdbcType;
|
||||
import org.hibernate.type.descriptor.jdbc.spi.JdbcTypeRegistry;
|
||||
|
||||
import jakarta.persistence.TemporalType;
|
||||
|
@ -103,10 +103,6 @@ public class SybaseLegacyDialect extends AbstractTransactSQLDialect {
|
|||
if ( precision == 19 && scale == 0 ) {
|
||||
return jdbcTypeRegistry.getDescriptor( Types.BIGINT );
|
||||
}
|
||||
case Types.TINYINT:
|
||||
if ( jtdsDriver ) {
|
||||
return jdbcTypeRegistry.getDescriptor( Types.SMALLINT );
|
||||
}
|
||||
}
|
||||
return super.resolveSqlTypeDescriptor(
|
||||
columnTypeName,
|
||||
|
@ -169,7 +165,7 @@ public class SybaseLegacyDialect extends AbstractTransactSQLDialect {
|
|||
final JdbcTypeRegistry jdbcTypeRegistry = typeContributions.getTypeConfiguration()
|
||||
.getJdbcTypeRegistry();
|
||||
if ( jtdsDriver ) {
|
||||
jdbcTypeRegistry.addDescriptor( Types.TINYINT, SmallIntJdbcType.INSTANCE );
|
||||
jdbcTypeRegistry.addDescriptor( Types.TINYINT, TinyIntAsSmallIntJdbcType.INSTANCE );
|
||||
|
||||
// The jTDS driver doesn't support the JDBC4 signatures using 'long length' for stream bindings
|
||||
jdbcTypeRegistry.addDescriptor( Types.CLOB, ClobJdbcType.CLOB_BINDING );
|
||||
|
|
|
@ -31,8 +31,10 @@ import org.hibernate.type.spi.TypeConfiguration;
|
|||
|
||||
import jakarta.persistence.EnumType;
|
||||
|
||||
import static org.hibernate.type.SqlTypes.CHAR;
|
||||
import static org.hibernate.type.SqlTypes.SMALLINT;
|
||||
import static org.hibernate.type.SqlTypes.TINYINT;
|
||||
import static org.hibernate.type.SqlTypes.VARCHAR;
|
||||
|
||||
/**
|
||||
* Resolution for {@linkplain Enum enum} mappings using {@link jakarta.persistence.Enumerated},
|
||||
|
@ -138,20 +140,20 @@ public class EnumeratedValueResolution<E extends Enum<E>,R> implements BasicValu
|
|||
if ( style == EnumType.ORDINAL ) {
|
||||
jdbcType = jdbcTypeRegistry.getDescriptor( enumJavaType.hasManyValues() ? SMALLINT : TINYINT );
|
||||
|
||||
final JavaType<Integer> jdbcJavaType = javaTypeRegistry.getDescriptor( Integer.class );
|
||||
final JavaType<Integer> jdbcJavaType = jdbcType.getJdbcRecommendedJavaTypeMapping(
|
||||
jdbcTypeIndicators.getColumnPrecision(),
|
||||
jdbcTypeIndicators.getColumnScale(),
|
||||
typeConfiguration
|
||||
);
|
||||
converter = new OrdinalEnumValueConverter<>( enumJavaType, jdbcType, jdbcJavaType );
|
||||
}
|
||||
else if ( style == EnumType.STRING ) {
|
||||
//noinspection rawtypes
|
||||
final JavaType jdbcJavaType;
|
||||
if ( jdbcTypeIndicators.getColumnLength() == 1 ) {
|
||||
jdbcJavaType = javaTypeRegistry.getDescriptor( Character.class );
|
||||
}
|
||||
else {
|
||||
jdbcJavaType = javaTypeRegistry.getDescriptor( String.class );
|
||||
}
|
||||
jdbcType = jdbcJavaType.getRecommendedJdbcType( jdbcTypeIndicators );
|
||||
//noinspection unchecked,rawtypes
|
||||
jdbcType = jdbcTypeRegistry.getDescriptor( jdbcTypeIndicators.getColumnLength() == 1 ? CHAR : VARCHAR );
|
||||
final JavaType<String> jdbcJavaType = jdbcType.getJdbcRecommendedJavaTypeMapping(
|
||||
jdbcTypeIndicators.getColumnPrecision(),
|
||||
jdbcTypeIndicators.getColumnScale(),
|
||||
typeConfiguration
|
||||
);
|
||||
converter = new NamedEnumValueConverter<>( enumJavaType, jdbcType, jdbcJavaType );
|
||||
}
|
||||
else {
|
||||
|
|
|
@ -374,8 +374,8 @@ public class InferredBasicValueResolver {
|
|||
BasicJavaType<N> explicitJavaType,
|
||||
JdbcType explicitJdbcType,
|
||||
MetadataBuildingContext context) {
|
||||
final JavaType<N> relationalJavaType = ordinalJavaType( explicitJavaType, context );
|
||||
final JdbcType jdbcType = ordinalJdbcType( explicitJdbcType, enumJavaType, context );
|
||||
final JavaType<N> relationalJavaType = ordinalJavaType( explicitJavaType, jdbcType, context );
|
||||
|
||||
return new EnumeratedValueResolution<>(
|
||||
jdbcType,
|
||||
|
@ -395,6 +395,7 @@ public class InferredBasicValueResolver {
|
|||
|
||||
private static <N extends Number> JavaType<N> ordinalJavaType(
|
||||
JavaType<N> explicitJavaType,
|
||||
JdbcType jdbcType,
|
||||
MetadataBuildingContext context) {
|
||||
if ( explicitJavaType != null ) {
|
||||
if ( !Integer.class.isAssignableFrom( explicitJavaType.getJavaTypeClass() ) ) {
|
||||
|
@ -407,7 +408,11 @@ public class InferredBasicValueResolver {
|
|||
return explicitJavaType;
|
||||
}
|
||||
else {
|
||||
return context.getMetadataCollector().getTypeConfiguration().getJavaTypeRegistry().getDescriptor( Integer.class );
|
||||
return jdbcType.getJdbcRecommendedJavaTypeMapping(
|
||||
null,
|
||||
null,
|
||||
context.getMetadataCollector().getTypeConfiguration()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -113,7 +113,7 @@ import org.hibernate.type.descriptor.jdbc.NCharJdbcType;
|
|||
import org.hibernate.type.descriptor.jdbc.NClobJdbcType;
|
||||
import org.hibernate.type.descriptor.jdbc.NVarcharJdbcType;
|
||||
import org.hibernate.type.descriptor.jdbc.NumericJdbcType;
|
||||
import org.hibernate.type.descriptor.jdbc.SmallIntJdbcType;
|
||||
import org.hibernate.type.descriptor.jdbc.TinyIntAsSmallIntJdbcType;
|
||||
import org.hibernate.type.descriptor.jdbc.spi.JdbcTypeRegistry;
|
||||
import org.hibernate.type.descriptor.sql.internal.CapacityDependentDdlType;
|
||||
import org.hibernate.type.descriptor.sql.internal.DdlTypeImpl;
|
||||
|
@ -1044,7 +1044,7 @@ public abstract class AbstractHANADialect extends Dialect {
|
|||
jdbcTypeRegistry.addDescriptor( Types.NCLOB, this.nClobTypeDescriptor );
|
||||
jdbcTypeRegistry.addDescriptor( Types.BLOB, this.blobTypeDescriptor );
|
||||
// tinyint is unsigned on HANA
|
||||
jdbcTypeRegistry.addDescriptor( Types.TINYINT, SmallIntJdbcType.INSTANCE );
|
||||
jdbcTypeRegistry.addDescriptor( Types.TINYINT, TinyIntAsSmallIntJdbcType.INSTANCE );
|
||||
if ( isUseUnicodeStringTypes() ) {
|
||||
jdbcTypeRegistry.addDescriptor( Types.VARCHAR, NVarcharJdbcType.INSTANCE );
|
||||
jdbcTypeRegistry.addDescriptor( Types.CHAR, NCharJdbcType.INSTANCE );
|
||||
|
|
|
@ -73,7 +73,7 @@ import org.hibernate.type.BasicTypeRegistry;
|
|||
import org.hibernate.type.StandardBasicTypes;
|
||||
import org.hibernate.type.descriptor.java.PrimitiveByteArrayJavaType;
|
||||
import org.hibernate.type.descriptor.jdbc.JdbcType;
|
||||
import org.hibernate.type.descriptor.jdbc.SmallIntJdbcType;
|
||||
import org.hibernate.type.descriptor.jdbc.TinyIntAsSmallIntJdbcType;
|
||||
import org.hibernate.type.descriptor.jdbc.UUIDJdbcType;
|
||||
import org.hibernate.type.descriptor.jdbc.XmlJdbcType;
|
||||
import org.hibernate.type.descriptor.jdbc.spi.JdbcTypeRegistry;
|
||||
|
@ -274,7 +274,7 @@ public class SQLServerDialect extends AbstractTransactSQLDialect {
|
|||
|
||||
typeContributions.getTypeConfiguration().getJdbcTypeRegistry().addDescriptor(
|
||||
Types.TINYINT,
|
||||
SmallIntJdbcType.INSTANCE
|
||||
TinyIntAsSmallIntJdbcType.INSTANCE
|
||||
);
|
||||
typeContributions.contributeJdbcType( XmlJdbcType.INSTANCE );
|
||||
typeContributions.contributeJdbcType( UUIDJdbcType.INSTANCE );
|
||||
|
|
|
@ -53,7 +53,7 @@ import org.hibernate.type.descriptor.jdbc.BlobJdbcType;
|
|||
import org.hibernate.type.descriptor.jdbc.ClobJdbcType;
|
||||
import org.hibernate.type.descriptor.jdbc.JdbcType;
|
||||
import org.hibernate.type.descriptor.jdbc.ObjectNullAsNullTypeJdbcType;
|
||||
import org.hibernate.type.descriptor.jdbc.SmallIntJdbcType;
|
||||
import org.hibernate.type.descriptor.jdbc.TinyIntAsSmallIntJdbcType;
|
||||
import org.hibernate.type.descriptor.jdbc.spi.JdbcTypeRegistry;
|
||||
|
||||
import jakarta.persistence.TemporalType;
|
||||
|
@ -107,10 +107,6 @@ public class SybaseDialect extends AbstractTransactSQLDialect {
|
|||
if ( precision == 19 && scale == 0 ) {
|
||||
return jdbcTypeRegistry.getDescriptor( Types.BIGINT );
|
||||
}
|
||||
case Types.TINYINT:
|
||||
if ( jtdsDriver ) {
|
||||
return jdbcTypeRegistry.getDescriptor( Types.SMALLINT );
|
||||
}
|
||||
}
|
||||
return super.resolveSqlTypeDescriptor(
|
||||
columnTypeName,
|
||||
|
@ -173,7 +169,7 @@ public class SybaseDialect extends AbstractTransactSQLDialect {
|
|||
final JdbcTypeRegistry jdbcTypeRegistry = typeContributions.getTypeConfiguration()
|
||||
.getJdbcTypeRegistry();
|
||||
if ( jtdsDriver ) {
|
||||
jdbcTypeRegistry.addDescriptor( Types.TINYINT, SmallIntJdbcType.INSTANCE );
|
||||
jdbcTypeRegistry.addDescriptor( Types.TINYINT, TinyIntAsSmallIntJdbcType.INSTANCE );
|
||||
|
||||
// The jTDS driver doesn't support the JDBC4 signatures using 'long length' for stream bindings
|
||||
jdbcTypeRegistry.addDescriptor( Types.CLOB, ClobJdbcType.CLOB_BINDING );
|
||||
|
|
|
@ -22,7 +22,7 @@ import org.hibernate.engine.spi.SessionFactoryImplementor;
|
|||
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||
import org.hibernate.internal.util.collections.CollectionHelper;
|
||||
import org.hibernate.metamodel.MappingMetamodel;
|
||||
import org.hibernate.metamodel.mapping.BasicValuedModelPart;
|
||||
import org.hibernate.metamodel.mapping.BasicValuedMapping;
|
||||
import org.hibernate.metamodel.mapping.Bindable;
|
||||
import org.hibernate.metamodel.mapping.EntityAssociationMapping;
|
||||
import org.hibernate.metamodel.mapping.EntityIdentifierMapping;
|
||||
|
@ -292,8 +292,8 @@ public class SqmUtil {
|
|||
if ( domainParamBinding.getType() instanceof JdbcMapping ) {
|
||||
jdbcMapping = (JdbcMapping) domainParamBinding.getType();
|
||||
}
|
||||
else if ( domainParamBinding.getBindType() instanceof BasicValuedModelPart ) {
|
||||
jdbcMapping = ( (BasicValuedModelPart) domainParamBinding.getType() ).getJdbcMapping();
|
||||
else if ( domainParamBinding.getBindType() instanceof BasicValuedMapping ) {
|
||||
jdbcMapping = ( (BasicValuedMapping) domainParamBinding.getType() ).getJdbcMapping();
|
||||
}
|
||||
else {
|
||||
jdbcMapping = null;
|
||||
|
|
|
@ -4948,10 +4948,10 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
|
|||
final Object value = literal.getLiteralValue();
|
||||
final Object sqlLiteralValue;
|
||||
// For converted query literals, we support both, the domain and relational java type
|
||||
if ( value == null || valueConverter.getDomainJavaType().getJavaTypeClass().isInstance( value ) ) {
|
||||
if ( value == null || valueConverter.getDomainJavaType().isInstance( value ) ) {
|
||||
sqlLiteralValue = valueConverter.toRelationalValue( value );
|
||||
}
|
||||
else if ( valueConverter.getRelationalJavaType().getJavaTypeClass().isInstance( value ) ) {
|
||||
else if ( valueConverter.getRelationalJavaType().isInstance( value ) ) {
|
||||
sqlLiteralValue = value;
|
||||
}
|
||||
else if ( basicValuedMapping instanceof EntityDiscriminatorMapping ) {
|
||||
|
@ -4963,6 +4963,15 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
|
|||
creationContext.getSessionFactory().getWrapperOptions()
|
||||
);
|
||||
}
|
||||
// In HQL, number literals might not match the relational java type exactly,
|
||||
// so we allow coercion between the number types
|
||||
else if ( Number.class.isAssignableFrom( valueConverter.getRelationalJavaType().getJavaTypeClass() )
|
||||
&& value instanceof Number ) {
|
||||
sqlLiteralValue = valueConverter.getRelationalJavaType().coerce(
|
||||
value,
|
||||
creationContext.getSessionFactory()::getTypeConfiguration
|
||||
);
|
||||
}
|
||||
else {
|
||||
throw new SqlTreeCreationException(
|
||||
String.format(
|
||||
|
|
|
@ -16,6 +16,7 @@ import java.util.function.BiConsumer;
|
|||
import org.hibernate.dialect.Dialect;
|
||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||
import org.hibernate.metamodel.mapping.BasicValuedMapping;
|
||||
import org.hibernate.metamodel.mapping.BasicValuedModelPart;
|
||||
import org.hibernate.metamodel.mapping.JdbcMapping;
|
||||
import org.hibernate.query.BindableType;
|
||||
import org.hibernate.query.spi.QueryParameterBinding;
|
||||
|
@ -28,6 +29,7 @@ import org.hibernate.sql.exec.spi.JdbcParameterBinder;
|
|||
import org.hibernate.sql.exec.spi.JdbcParameterBinding;
|
||||
import org.hibernate.sql.exec.spi.JdbcParameterBindings;
|
||||
import org.hibernate.type.BasicTypeReference;
|
||||
import org.hibernate.type.descriptor.converter.spi.BasicValueConverter;
|
||||
|
||||
/**
|
||||
* Standard implementation of JdbcParameterBindings
|
||||
|
@ -77,35 +79,62 @@ public class JdbcParameterBindingsImpl implements JdbcParameterBindings {
|
|||
throw new IllegalArgumentException( "Could not resolve NativeQuery parameter type : `" + param + "`");
|
||||
}
|
||||
|
||||
final BasicValueConverter valueConverter = jdbcMapping == null ? null : jdbcMapping.getValueConverter();
|
||||
|
||||
if ( binding.isMultiValued() ) {
|
||||
final Collection<?> bindValues = binding.getBindValues();
|
||||
final int bindValueCount = bindValues.size();
|
||||
Object lastBindValue = null;
|
||||
for ( Object bindValue : bindValues ) {
|
||||
final JdbcParameterImpl jdbcParameter = new JdbcParameterImpl( jdbcMapping );
|
||||
jdbcParameterBinders.add( jdbcParameter );
|
||||
addBinding( jdbcParameter, new JdbcParameterBindingImpl( jdbcMapping, bindValue ) );
|
||||
lastBindValue = bindValue;
|
||||
}
|
||||
final int bindValueMaxCount = NativeQueryImpl.determineBindValueMaxCount(
|
||||
paddingEnabled,
|
||||
inExprLimit,
|
||||
bindValueCount
|
||||
);
|
||||
if ( bindValueMaxCount != bindValueCount ) {
|
||||
for ( int i = bindValueCount; i < bindValueMaxCount; i++ ) {
|
||||
Object lastBindValue = null;
|
||||
if ( valueConverter != null ) {
|
||||
for ( Object bindValue : bindValues ) {
|
||||
final JdbcParameterImpl jdbcParameter = new JdbcParameterImpl( jdbcMapping );
|
||||
jdbcParameterBinders.add( jdbcParameter );
|
||||
lastBindValue = bindValue == null ? null : valueConverter.toRelationalValue( bindValue );
|
||||
addBinding( jdbcParameter, new JdbcParameterBindingImpl( jdbcMapping, lastBindValue ) );
|
||||
}
|
||||
if ( bindValueMaxCount != bindValueCount ) {
|
||||
for ( int i = bindValueCount; i < bindValueMaxCount; i++ ) {
|
||||
final JdbcParameterImpl jdbcParameter = new JdbcParameterImpl( jdbcMapping );
|
||||
jdbcParameterBinders.add( jdbcParameter );
|
||||
addBinding( jdbcParameter, new JdbcParameterBindingImpl( jdbcMapping, lastBindValue ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
for ( Object bindValue : bindValues ) {
|
||||
final JdbcParameterImpl jdbcParameter = new JdbcParameterImpl( jdbcMapping );
|
||||
jdbcParameterBinders.add( jdbcParameter );
|
||||
addBinding( jdbcParameter, new JdbcParameterBindingImpl( jdbcMapping, bindValue ) );
|
||||
lastBindValue = bindValue;
|
||||
}
|
||||
if ( bindValueMaxCount != bindValueCount ) {
|
||||
for ( int i = bindValueCount; i < bindValueMaxCount; i++ ) {
|
||||
final JdbcParameterImpl jdbcParameter = new JdbcParameterImpl( jdbcMapping );
|
||||
jdbcParameterBinders.add( jdbcParameter );
|
||||
addBinding( jdbcParameter, new JdbcParameterBindingImpl( jdbcMapping, lastBindValue ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
final Object bindValue;
|
||||
if ( valueConverter != null && binding.getBindValue() != null ) {
|
||||
bindValue = valueConverter.toRelationalValue( binding.getBindValue() );
|
||||
}
|
||||
else {
|
||||
bindValue = binding.getBindValue();
|
||||
}
|
||||
|
||||
final JdbcParameterImpl jdbcParameter = new JdbcParameterImpl( jdbcMapping );
|
||||
jdbcParameterBinders.add( jdbcParameter );
|
||||
addBinding(
|
||||
jdbcParameter,
|
||||
new JdbcParameterBindingImpl( jdbcMapping, binding.getBindValue() )
|
||||
new JdbcParameterBindingImpl( jdbcMapping, bindValue )
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -87,7 +87,7 @@ public abstract class AbstractStandardBasicType<T>
|
|||
}
|
||||
|
||||
@Override
|
||||
public JdbcLiteralFormatter getJdbcLiteralFormatter() {
|
||||
public JdbcLiteralFormatter<T> getJdbcLiteralFormatter() {
|
||||
return jdbcLiteralFormatter;
|
||||
}
|
||||
|
||||
|
|
|
@ -6,22 +6,9 @@
|
|||
*/
|
||||
package org.hibernate.type;
|
||||
|
||||
import java.lang.reflect.Array;
|
||||
import java.sql.CallableStatement;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
|
||||
import org.hibernate.type.descriptor.converter.spi.BasicValueConverter;
|
||||
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.JdbcLiteralFormatter;
|
||||
import org.hibernate.type.descriptor.jdbc.JdbcType;
|
||||
import org.hibernate.type.descriptor.jdbc.JdbcTypeIndicators;
|
||||
import org.hibernate.type.descriptor.jdbc.internal.JdbcLiteralFormatterArray;
|
||||
import org.hibernate.type.spi.TypeConfiguration;
|
||||
|
||||
/**
|
||||
* A type that maps between {@link java.sql.Types#ARRAY ARRAY} and {@code T[]}
|
||||
|
@ -35,118 +22,11 @@ public class BasicArrayType<T>
|
|||
|
||||
private final BasicType<T> baseDescriptor;
|
||||
private final String name;
|
||||
private final ValueBinder<T[]> jdbcValueBinder;
|
||||
private final ValueExtractor<T[]> jdbcValueExtractor;
|
||||
private final JdbcLiteralFormatter<T[]> jdbcLiteralFormatter;
|
||||
|
||||
public BasicArrayType(BasicType<T> baseDescriptor, JdbcType arrayJdbcType, JavaType<T[]> arrayTypeDescriptor) {
|
||||
super( arrayJdbcType, arrayTypeDescriptor );
|
||||
this.baseDescriptor = baseDescriptor;
|
||||
this.name = baseDescriptor.getName() + "[]";
|
||||
final ValueBinder<T[]> jdbcValueBinder = super.getJdbcValueBinder();
|
||||
final ValueExtractor<T[]> jdbcValueExtractor = super.getJdbcValueExtractor();
|
||||
final JdbcLiteralFormatter jdbcLiteralFormatter = super.getJdbcLiteralFormatter();
|
||||
//noinspection unchecked
|
||||
final BasicValueConverter<T, Object> valueConverter = (BasicValueConverter<T, Object>) baseDescriptor.getValueConverter();
|
||||
if ( valueConverter != null ) {
|
||||
this.jdbcValueBinder = new ValueBinder<>() {
|
||||
@Override
|
||||
public void bind(PreparedStatement st, T[] value, int index, WrapperOptions options)
|
||||
throws SQLException {
|
||||
jdbcValueBinder.bind( st, getValue( value, valueConverter, options ), index, options );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void bind(CallableStatement st, T[] value, String name, WrapperOptions options)
|
||||
throws SQLException {
|
||||
jdbcValueBinder.bind( st, getValue( value, valueConverter, options ), name, options );
|
||||
}
|
||||
|
||||
private T[] getValue(
|
||||
T[] value,
|
||||
BasicValueConverter<T, Object> valueConverter,
|
||||
WrapperOptions options) {
|
||||
if ( value == null ) {
|
||||
return null;
|
||||
}
|
||||
final JdbcType elementJdbcType = baseDescriptor.getJdbcType();
|
||||
final TypeConfiguration typeConfiguration = options.getSessionFactory().getTypeConfiguration();
|
||||
final JdbcType underlyingJdbcType = typeConfiguration.getJdbcTypeRegistry()
|
||||
.getDescriptor( elementJdbcType.getDefaultSqlTypeCode() );
|
||||
final Class<?> preferredJavaTypeClass = underlyingJdbcType.getPreferredJavaTypeClass( options );
|
||||
final Class<?> elementJdbcJavaTypeClass;
|
||||
if ( preferredJavaTypeClass == null ) {
|
||||
elementJdbcJavaTypeClass = underlyingJdbcType.getJdbcRecommendedJavaTypeMapping(
|
||||
null,
|
||||
null,
|
||||
typeConfiguration
|
||||
).getJavaTypeClass();
|
||||
}
|
||||
else {
|
||||
elementJdbcJavaTypeClass = preferredJavaTypeClass;
|
||||
}
|
||||
|
||||
if ( value.getClass().getComponentType() == elementJdbcJavaTypeClass ) {
|
||||
return value;
|
||||
}
|
||||
final Object[] array = (Object[]) Array.newInstance( elementJdbcJavaTypeClass, value.length );
|
||||
for ( int i = 0; i < value.length; i++ ) {
|
||||
array[i] = valueConverter.getRelationalJavaType().unwrap(
|
||||
valueConverter.toRelationalValue( value[i] ),
|
||||
elementJdbcJavaTypeClass,
|
||||
options
|
||||
);
|
||||
}
|
||||
//noinspection unchecked
|
||||
return (T[]) array;
|
||||
}
|
||||
};
|
||||
this.jdbcValueExtractor = new ValueExtractor<T[]>() {
|
||||
@Override
|
||||
public T[] extract(ResultSet rs, int paramIndex, WrapperOptions options) throws SQLException {
|
||||
return getValue( jdbcValueExtractor.extract( rs, paramIndex, options ), valueConverter );
|
||||
}
|
||||
|
||||
@Override
|
||||
public T[] extract(CallableStatement statement, int paramIndex, WrapperOptions options)
|
||||
throws SQLException {
|
||||
return getValue( jdbcValueExtractor.extract( statement, paramIndex, options ), valueConverter );
|
||||
}
|
||||
|
||||
@Override
|
||||
public T[] extract(CallableStatement statement, String paramName, WrapperOptions options)
|
||||
throws SQLException {
|
||||
return getValue( jdbcValueExtractor.extract( statement, paramName, options ), valueConverter );
|
||||
}
|
||||
|
||||
private T[] getValue(T[] value, BasicValueConverter<T, Object> valueConverter) {
|
||||
if ( value == null ) {
|
||||
return null;
|
||||
}
|
||||
if ( value.getClass().getComponentType() == valueConverter.getDomainJavaType().getJavaTypeClass() ) {
|
||||
return value;
|
||||
}
|
||||
//noinspection unchecked
|
||||
final T[] array = (T[]) Array.newInstance(
|
||||
valueConverter.getDomainJavaType().getJavaTypeClass(),
|
||||
value.length
|
||||
);
|
||||
for ( int i = 0; i < value.length; i++ ) {
|
||||
array[i] = valueConverter.toDomainValue( value[i] );
|
||||
}
|
||||
return array;
|
||||
}
|
||||
};
|
||||
this.jdbcLiteralFormatter = new JdbcLiteralFormatterArray(
|
||||
baseDescriptor.getJavaTypeDescriptor(),
|
||||
jdbcLiteralFormatter
|
||||
);
|
||||
}
|
||||
else {
|
||||
this.jdbcValueBinder = jdbcValueBinder;
|
||||
this.jdbcValueExtractor = jdbcValueExtractor;
|
||||
this.jdbcLiteralFormatter = jdbcLiteralFormatter;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -164,21 +44,6 @@ public class BasicArrayType<T>
|
|||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ValueExtractor<T[]> getJdbcValueExtractor() {
|
||||
return jdbcValueExtractor;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ValueBinder<T[]> getJdbcValueBinder() {
|
||||
return jdbcValueBinder;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JdbcLiteralFormatter getJdbcLiteralFormatter() {
|
||||
return jdbcLiteralFormatter;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <X> BasicType<X> resolveIndicatedType(JdbcTypeIndicators indicators, JavaType<X> domainJtd) {
|
||||
// TODO: maybe fallback to some encoding by default if the DB doesn't support arrays natively?
|
||||
|
|
|
@ -25,7 +25,10 @@ public class BasicCollectionType<C extends Collection<E>, E>
|
|||
private final BasicType<E> baseDescriptor;
|
||||
private final String name;
|
||||
|
||||
public BasicCollectionType(BasicType<E> baseDescriptor, JdbcType arrayJdbcType, BasicCollectionJavaType<C, E> collectionTypeDescriptor) {
|
||||
public BasicCollectionType(
|
||||
BasicType<E> baseDescriptor,
|
||||
JdbcType arrayJdbcType,
|
||||
BasicCollectionJavaType<C, E> collectionTypeDescriptor) {
|
||||
super( arrayJdbcType, collectionTypeDescriptor );
|
||||
this.baseDescriptor = baseDescriptor;
|
||||
this.name = determineName( collectionTypeDescriptor, baseDescriptor );
|
||||
|
|
|
@ -0,0 +1,65 @@
|
|||
/*
|
||||
* 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;
|
||||
|
||||
import org.hibernate.type.descriptor.ValueBinder;
|
||||
import org.hibernate.type.descriptor.ValueExtractor;
|
||||
import org.hibernate.type.descriptor.converter.spi.BasicValueConverter;
|
||||
import org.hibernate.type.descriptor.java.JavaType;
|
||||
import org.hibernate.type.descriptor.jdbc.JdbcLiteralFormatter;
|
||||
import org.hibernate.type.descriptor.jdbc.JdbcType;
|
||||
|
||||
/**
|
||||
* A converted basic array type.
|
||||
*
|
||||
* @author Christian Beikov
|
||||
*/
|
||||
public class ConvertedBasicArrayType<T> extends BasicArrayType<T> {
|
||||
|
||||
private final BasicValueConverter<T[], ?> converter;
|
||||
private final ValueExtractor<T[]> jdbcValueExtractor;
|
||||
private final ValueBinder<T[]> jdbcValueBinder;
|
||||
private final JdbcLiteralFormatter<T[]> jdbcLiteralFormatter;
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public ConvertedBasicArrayType(
|
||||
BasicType<T> baseDescriptor,
|
||||
JdbcType arrayJdbcType,
|
||||
JavaType<T[]> arrayTypeDescriptor,
|
||||
BasicValueConverter<T[], ?> converter) {
|
||||
super( baseDescriptor, arrayJdbcType, arrayTypeDescriptor );
|
||||
this.converter = converter;
|
||||
this.jdbcValueBinder = (ValueBinder<T[]>) arrayJdbcType.getBinder( converter.getRelationalJavaType() );
|
||||
this.jdbcValueExtractor = (ValueExtractor<T[]>) arrayJdbcType.getExtractor( converter.getRelationalJavaType() );
|
||||
this.jdbcLiteralFormatter = (JdbcLiteralFormatter<T[]>) arrayJdbcType.getJdbcLiteralFormatter( converter.getRelationalJavaType() );
|
||||
}
|
||||
|
||||
@Override
|
||||
public BasicValueConverter<T[], ?> getValueConverter() {
|
||||
return converter;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JavaType<?> getJdbcJavaType() {
|
||||
return converter.getRelationalJavaType();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ValueExtractor<T[]> getJdbcValueExtractor() {
|
||||
return jdbcValueExtractor;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ValueBinder<T[]> getJdbcValueBinder() {
|
||||
return jdbcValueBinder;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JdbcLiteralFormatter<T[]> getJdbcLiteralFormatter() {
|
||||
return jdbcLiteralFormatter;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,68 @@
|
|||
/*
|
||||
* 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;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
import org.hibernate.type.descriptor.ValueBinder;
|
||||
import org.hibernate.type.descriptor.ValueExtractor;
|
||||
import org.hibernate.type.descriptor.converter.spi.BasicValueConverter;
|
||||
import org.hibernate.type.descriptor.java.JavaType;
|
||||
import org.hibernate.type.descriptor.java.spi.BasicCollectionJavaType;
|
||||
import org.hibernate.type.descriptor.jdbc.JdbcLiteralFormatter;
|
||||
import org.hibernate.type.descriptor.jdbc.JdbcType;
|
||||
|
||||
/**
|
||||
* A converted basic array type.
|
||||
*
|
||||
* @author Christian Beikov
|
||||
*/
|
||||
public class ConvertedBasicCollectionType<C extends Collection<E>, E> extends BasicCollectionType<C, E> {
|
||||
|
||||
private final BasicValueConverter<C, ?> converter;
|
||||
private final ValueExtractor<C> jdbcValueExtractor;
|
||||
private final ValueBinder<C> jdbcValueBinder;
|
||||
private final JdbcLiteralFormatter<C> jdbcLiteralFormatter;
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public ConvertedBasicCollectionType(
|
||||
BasicType<E> baseDescriptor,
|
||||
JdbcType arrayJdbcType,
|
||||
BasicCollectionJavaType<C, E> arrayTypeDescriptor,
|
||||
BasicValueConverter<C, ?> converter) {
|
||||
super( baseDescriptor, arrayJdbcType, arrayTypeDescriptor );
|
||||
this.converter = converter;
|
||||
this.jdbcValueBinder = (ValueBinder<C>) arrayJdbcType.getBinder( converter.getRelationalJavaType() );
|
||||
this.jdbcValueExtractor = (ValueExtractor<C>) arrayJdbcType.getExtractor( converter.getRelationalJavaType() );
|
||||
this.jdbcLiteralFormatter = (JdbcLiteralFormatter<C>) arrayJdbcType.getJdbcLiteralFormatter( converter.getRelationalJavaType() );
|
||||
}
|
||||
|
||||
@Override
|
||||
public BasicValueConverter<C, ?> getValueConverter() {
|
||||
return converter;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JavaType<?> getJdbcJavaType() {
|
||||
return converter.getRelationalJavaType();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ValueExtractor<C> getJdbcValueExtractor() {
|
||||
return jdbcValueExtractor;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ValueBinder<C> getJdbcValueBinder() {
|
||||
return jdbcValueBinder;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JdbcLiteralFormatter<C> getJdbcLiteralFormatter() {
|
||||
return jdbcLiteralFormatter;
|
||||
}
|
||||
}
|
|
@ -199,7 +199,7 @@ public class EnumType<T extends Enum<T>>
|
|||
}
|
||||
}
|
||||
|
||||
private JavaType<?> resolveRelationalJavaType(
|
||||
private JavaType<? extends Number> resolveRelationalJavaType(
|
||||
LocalJdbcTypeIndicators indicators,
|
||||
EnumJavaType<?> enumJavaType) {
|
||||
return enumJavaType.getRecommendedJdbcType( indicators )
|
||||
|
@ -264,19 +264,15 @@ public class EnumType<T extends Enum<T>>
|
|||
final int type = Integer.decode( (String) parameters.get( TYPE ) );
|
||||
return getConverterForType( enumJavaType, localIndicators, type );
|
||||
}
|
||||
|
||||
final JavaType<? extends Number> relationalJavaType = resolveRelationalJavaType( localIndicators, enumJavaType );
|
||||
// the fallback
|
||||
return new OrdinalEnumValueConverter<>(
|
||||
enumJavaType,
|
||||
getIntegerType().getRecommendedJdbcType( localIndicators ),
|
||||
getIntegerType()
|
||||
relationalJavaType.getRecommendedJdbcType( localIndicators ),
|
||||
relationalJavaType
|
||||
);
|
||||
}
|
||||
|
||||
private JavaType<Integer> getIntegerType() {
|
||||
return typeConfiguration.getJavaTypeRegistry().getDescriptor(Integer.class);
|
||||
}
|
||||
|
||||
private JavaType<String> getStringType() {
|
||||
return typeConfiguration.getJavaTypeRegistry().getDescriptor(String.class);
|
||||
}
|
||||
|
@ -293,10 +289,11 @@ public class EnumType<T extends Enum<T>>
|
|||
);
|
||||
}
|
||||
else {
|
||||
final JavaType<? extends Number> relationalJavaType = resolveRelationalJavaType( localIndicators, enumJavaType );
|
||||
return new OrdinalEnumValueConverter<>(
|
||||
enumJavaType,
|
||||
getIntegerType().getRecommendedJdbcType( localIndicators ),
|
||||
getIntegerType()
|
||||
relationalJavaType.getRecommendedJdbcType( localIndicators ),
|
||||
relationalJavaType
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -306,10 +303,11 @@ public class EnumType<T extends Enum<T>>
|
|||
LocalJdbcTypeIndicators localIndicators,
|
||||
int type) {
|
||||
if ( isNumericType(type) ) {
|
||||
final JavaType<? extends Number> relationalJavaType = resolveRelationalJavaType( localIndicators, enumJavaType );
|
||||
return new OrdinalEnumValueConverter<>(
|
||||
enumJavaType,
|
||||
getIntegerType().getRecommendedJdbcType( localIndicators ),
|
||||
getIntegerType()
|
||||
relationalJavaType.getRecommendedJdbcType( localIndicators ),
|
||||
relationalJavaType
|
||||
);
|
||||
}
|
||||
else if ( isCharacterType(type) ) {
|
||||
|
|
|
@ -0,0 +1,84 @@
|
|||
/*
|
||||
* 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 java.lang.reflect.Array;
|
||||
|
||||
import org.hibernate.type.descriptor.converter.spi.BasicValueConverter;
|
||||
import org.hibernate.type.descriptor.java.JavaType;
|
||||
|
||||
/**
|
||||
* Handles conversion to/from an array of a converted element type.
|
||||
*/
|
||||
public class ArrayConverter<X, Y> implements BasicValueConverter<X, Y> {
|
||||
|
||||
private final BasicValueConverter<Object, Object> elementConverter;
|
||||
private final JavaType<X> domainJavaType;
|
||||
private final JavaType<Y> relationalJavaType;
|
||||
|
||||
public ArrayConverter(
|
||||
BasicValueConverter<Object, Object> elementConverter,
|
||||
JavaType<X> domainJavaType,
|
||||
JavaType<Y> relationalJavaType) {
|
||||
this.elementConverter = elementConverter;
|
||||
this.domainJavaType = domainJavaType;
|
||||
this.relationalJavaType = relationalJavaType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public X toDomainValue(Y relationalForm) {
|
||||
if ( relationalForm == null ) {
|
||||
return null;
|
||||
}
|
||||
if ( relationalForm.getClass().getComponentType() == elementConverter.getDomainJavaType().getJavaTypeClass() ) {
|
||||
//noinspection unchecked
|
||||
return (X) relationalForm;
|
||||
}
|
||||
final Object[] relationalArray = (Object[]) relationalForm;
|
||||
final Object[] domainArray = (Object[]) Array.newInstance(
|
||||
elementConverter.getDomainJavaType().getJavaTypeClass(),
|
||||
relationalArray.length
|
||||
);
|
||||
for ( int i = 0; i < relationalArray.length; i++ ) {
|
||||
domainArray[i] = elementConverter.toDomainValue( relationalArray[i] );
|
||||
}
|
||||
//noinspection unchecked
|
||||
return (X) domainArray;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Y toRelationalValue(X domainForm) {
|
||||
if ( domainForm == null ) {
|
||||
return null;
|
||||
}
|
||||
if ( domainForm.getClass().getComponentType() == elementConverter.getRelationalJavaType().getJavaTypeClass() ) {
|
||||
//noinspection unchecked
|
||||
return (Y) domainForm;
|
||||
}
|
||||
final Object[] domainArray = (Object[]) domainForm;
|
||||
final Object[] relationalArray = (Object[]) Array.newInstance(
|
||||
elementConverter.getRelationalJavaType().getJavaTypeClass(),
|
||||
domainArray.length
|
||||
);
|
||||
for ( int i = 0; i < domainArray.length; i++ ) {
|
||||
relationalArray[i] = elementConverter.toRelationalValue( domainArray[i] );
|
||||
}
|
||||
//noinspection unchecked
|
||||
return (Y) relationalArray;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JavaType<X> getDomainJavaType() {
|
||||
return domainJavaType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JavaType<Y> getRelationalJavaType() {
|
||||
return relationalJavaType;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,74 @@
|
|||
/*
|
||||
* 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 java.lang.reflect.Array;
|
||||
import java.util.Collection;
|
||||
|
||||
import org.hibernate.type.descriptor.converter.spi.BasicValueConverter;
|
||||
import org.hibernate.type.descriptor.java.JavaType;
|
||||
import org.hibernate.type.descriptor.java.spi.BasicCollectionJavaType;
|
||||
|
||||
/**
|
||||
* Handles conversion to/from a collection of a converted element type.
|
||||
*/
|
||||
public class CollectionConverter<X extends Collection<Object>, Y> implements BasicValueConverter<X, Y> {
|
||||
|
||||
private final BasicValueConverter<Object, Object> elementConverter;
|
||||
private final BasicCollectionJavaType<X, ?> domainJavaType;
|
||||
private final JavaType<Y> relationalJavaType;
|
||||
|
||||
public CollectionConverter(
|
||||
BasicValueConverter<Object, Object> elementConverter,
|
||||
BasicCollectionJavaType<X, ?> domainJavaType,
|
||||
JavaType<Y> relationalJavaType) {
|
||||
this.elementConverter = elementConverter;
|
||||
this.domainJavaType = domainJavaType;
|
||||
this.relationalJavaType = relationalJavaType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public X toDomainValue(Y relationalForm) {
|
||||
if ( relationalForm == null ) {
|
||||
return null;
|
||||
}
|
||||
final Object[] relationalArray = (Object[]) relationalForm;
|
||||
final X domainForm = domainJavaType.getSemantics().instantiateRaw( relationalArray.length, null );
|
||||
for ( int i = 0; i < relationalArray.length; i++ ) {
|
||||
domainForm.add( elementConverter.toDomainValue( relationalArray[i] ) );
|
||||
}
|
||||
return domainForm;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Y toRelationalValue(X domainForm) {
|
||||
if ( domainForm == null ) {
|
||||
return null;
|
||||
}
|
||||
final Object[] relationalArray = (Object[]) Array.newInstance(
|
||||
elementConverter.getRelationalJavaType().getJavaTypeClass(),
|
||||
domainForm.size()
|
||||
);
|
||||
int i = 0;
|
||||
for ( Object domainValue : domainForm ) {
|
||||
relationalArray[i++] = elementConverter.toRelationalValue( domainValue );
|
||||
}
|
||||
//noinspection unchecked
|
||||
return (Y) relationalArray;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JavaType<X> getDomainJavaType() {
|
||||
return domainJavaType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JavaType<Y> getRelationalJavaType() {
|
||||
return relationalJavaType;
|
||||
}
|
||||
|
||||
}
|
|
@ -40,9 +40,9 @@ public class OrdinalEnumValueConverter<E extends Enum<E>, N extends Number> impl
|
|||
return enumJavaType.fromOrdinal( relationalForm == null ? null : relationalForm.intValue() );
|
||||
}
|
||||
|
||||
@Override @SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public N toRelationalValue(E domainForm) {
|
||||
return (N) enumJavaType.toOrdinal( domainForm );
|
||||
return relationalJavaType.wrap( enumJavaType.toOrdinal( domainForm ), null );
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -6,14 +6,17 @@
|
|||
*/
|
||||
package org.hibernate.type.descriptor.java;
|
||||
|
||||
import java.lang.reflect.Array;
|
||||
import java.sql.Types;
|
||||
|
||||
import org.hibernate.dialect.Dialect;
|
||||
import org.hibernate.engine.jdbc.spi.JdbcServices;
|
||||
import org.hibernate.tool.schema.extract.spi.ColumnTypeInformation;
|
||||
import org.hibernate.type.descriptor.converter.internal.ArrayConverter;
|
||||
import org.hibernate.type.BasicArrayType;
|
||||
import org.hibernate.type.BasicPluralType;
|
||||
import org.hibernate.type.BasicType;
|
||||
import org.hibernate.type.ConvertedBasicArrayType;
|
||||
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.JdbcTypeIndicators;
|
||||
|
@ -66,21 +69,46 @@ public abstract class AbstractArrayJavaType<T, E> extends AbstractClassJavaType<
|
|||
if ( elementType instanceof BasicPluralType<?, ?> || elementJavaTypeClass != null && elementJavaTypeClass.isArray() ) {
|
||||
return null;
|
||||
}
|
||||
return typeConfiguration.standardBasicTypeForJavaType(
|
||||
getJavaType(),
|
||||
javaType -> {
|
||||
JdbcType arrayJdbcType = typeConfiguration.getJdbcTypeRegistry().getDescriptor( Types.ARRAY );
|
||||
if ( arrayJdbcType instanceof ArrayJdbcType ) {
|
||||
arrayJdbcType = ( (ArrayJdbcType) arrayJdbcType ).resolveType(
|
||||
typeConfiguration,
|
||||
dialect,
|
||||
elementType,
|
||||
columnTypeInformation
|
||||
);
|
||||
final BasicValueConverter<E, ?> valueConverter = elementType.getValueConverter();
|
||||
if ( valueConverter == null ) {
|
||||
return typeConfiguration.standardBasicTypeForJavaType(
|
||||
getJavaType(),
|
||||
javaType -> {
|
||||
JdbcType arrayJdbcType = typeConfiguration.getJdbcTypeRegistry().getDescriptor( Types.ARRAY );
|
||||
if ( arrayJdbcType instanceof ArrayJdbcType ) {
|
||||
arrayJdbcType = ( (ArrayJdbcType) arrayJdbcType ).resolveType(
|
||||
typeConfiguration,
|
||||
dialect,
|
||||
elementType,
|
||||
columnTypeInformation
|
||||
);
|
||||
}
|
||||
//noinspection unchecked,rawtypes
|
||||
return new BasicArrayType( elementType, arrayJdbcType, javaType );
|
||||
}
|
||||
//noinspection unchecked,rawtypes
|
||||
return new BasicArrayType( elementType, arrayJdbcType, javaType );
|
||||
}
|
||||
);
|
||||
);
|
||||
}
|
||||
else {
|
||||
final JavaType<Object> relationalJavaType = typeConfiguration.getJavaTypeRegistry().getDescriptor(
|
||||
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
|
||||
return new ConvertedBasicArrayType(
|
||||
elementType,
|
||||
arrayJdbcType,
|
||||
this,
|
||||
new ArrayConverter( valueConverter, this, relationalJavaType )
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,10 +18,13 @@ import org.hibernate.engine.jdbc.BinaryStream;
|
|||
import org.hibernate.engine.jdbc.internal.BinaryStreamImpl;
|
||||
import org.hibernate.internal.util.SerializationHelper;
|
||||
import org.hibernate.tool.schema.extract.spi.ColumnTypeInformation;
|
||||
import org.hibernate.type.descriptor.converter.internal.ArrayConverter;
|
||||
import org.hibernate.type.BasicArrayType;
|
||||
import org.hibernate.type.BasicPluralType;
|
||||
import org.hibernate.type.BasicType;
|
||||
import org.hibernate.type.ConvertedBasicArrayType;
|
||||
import org.hibernate.type.descriptor.WrapperOptions;
|
||||
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.spi.TypeConfiguration;
|
||||
|
@ -65,21 +68,47 @@ public class ArrayJavaType<T> extends AbstractArrayJavaType<T[], T> {
|
|||
// Register the array type as that will be resolved in the next step
|
||||
typeConfiguration.getJavaTypeRegistry().addDescriptor( arrayJavaType );
|
||||
}
|
||||
return typeConfiguration.standardBasicTypeForJavaType(
|
||||
arrayJavaType.getJavaType(),
|
||||
javaType -> {
|
||||
JdbcType arrayJdbcType = typeConfiguration.getJdbcTypeRegistry().getDescriptor( Types.ARRAY );
|
||||
if ( arrayJdbcType instanceof ArrayJdbcType ) {
|
||||
arrayJdbcType = ( (ArrayJdbcType) arrayJdbcType ).resolveType(
|
||||
typeConfiguration,
|
||||
dialect,
|
||||
elementType,
|
||||
columnTypeInformation
|
||||
);
|
||||
//noinspection unchecked
|
||||
final BasicValueConverter<Object, Object> valueConverter = (BasicValueConverter<Object, Object>) elementType.getValueConverter();
|
||||
if ( valueConverter == null ) {
|
||||
return typeConfiguration.standardBasicTypeForJavaType(
|
||||
arrayJavaType.getJavaType(),
|
||||
javaType -> {
|
||||
JdbcType arrayJdbcType = typeConfiguration.getJdbcTypeRegistry().getDescriptor( Types.ARRAY );
|
||||
if ( arrayJdbcType instanceof ArrayJdbcType ) {
|
||||
arrayJdbcType = ( (ArrayJdbcType) arrayJdbcType ).resolveType(
|
||||
typeConfiguration,
|
||||
dialect,
|
||||
elementType,
|
||||
columnTypeInformation
|
||||
);
|
||||
}
|
||||
return new BasicArrayType<>( elementType, arrayJdbcType, javaType );
|
||||
}
|
||||
return new BasicArrayType<>( elementType, arrayJdbcType, javaType );
|
||||
}
|
||||
);
|
||||
);
|
||||
}
|
||||
else {
|
||||
final JavaType<Object> relationalJavaType = typeConfiguration.getJavaTypeRegistry().getDescriptor(
|
||||
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
|
||||
return new ConvertedBasicArrayType<>(
|
||||
elementType,
|
||||
arrayJdbcType,
|
||||
arrayJavaType,
|
||||
new ArrayConverter<>( valueConverter, arrayJavaType, relationalJavaType )
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -15,6 +15,7 @@ import java.util.Arrays;
|
|||
import org.hibernate.HibernateException;
|
||||
import org.hibernate.engine.jdbc.BinaryStream;
|
||||
import org.hibernate.engine.jdbc.internal.BinaryStreamImpl;
|
||||
import org.hibernate.internal.util.SerializationHelper;
|
||||
import org.hibernate.type.descriptor.WrapperOptions;
|
||||
|
||||
/**
|
||||
|
@ -24,6 +25,7 @@ import org.hibernate.type.descriptor.WrapperOptions;
|
|||
*/
|
||||
public class ByteArrayJavaType extends AbstractClassJavaType<Byte[]> {
|
||||
public static final ByteArrayJavaType INSTANCE = new ByteArrayJavaType();
|
||||
private static final Byte[] EMPTY_BYTE_ARRAY = new Byte[0];
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public ByteArrayJavaType() {
|
||||
|
@ -117,6 +119,30 @@ public class ByteArrayJavaType extends AbstractClassJavaType<Byte[]> {
|
|||
throw new HibernateException( "Unable to access lob stream", e );
|
||||
}
|
||||
}
|
||||
if ( value instanceof java.sql.Array ) {
|
||||
try {
|
||||
//noinspection unchecked
|
||||
value = (X) ( (java.sql.Array) value ).getArray();
|
||||
if ( value instanceof Byte[] ) {
|
||||
return (Byte[]) value;
|
||||
}
|
||||
else if ( value instanceof Object[] ) {
|
||||
final Object[] array = (Object[]) value;
|
||||
if ( array.length == 0 ) {
|
||||
return EMPTY_BYTE_ARRAY;
|
||||
}
|
||||
final Byte[] bytes = new Byte[array.length];
|
||||
for ( int i = 0; i < array.length; i++ ) {
|
||||
bytes[i] = ByteJavaType.INSTANCE.wrap( array[i], options );
|
||||
}
|
||||
return bytes;
|
||||
}
|
||||
}
|
||||
catch ( SQLException ex ) {
|
||||
// This basically shouldn't happen unless you've lost connection to the database.
|
||||
throw new HibernateException( ex );
|
||||
}
|
||||
}
|
||||
|
||||
throw unknownWrap( value.getClass() );
|
||||
}
|
||||
|
@ -125,21 +151,16 @@ public class ByteArrayJavaType extends AbstractClassJavaType<Byte[]> {
|
|||
if ( bytes == null ) {
|
||||
return null;
|
||||
}
|
||||
final Byte[] result = new Byte[bytes.length];
|
||||
for ( int i = 0; i < bytes.length; i++ ) {
|
||||
result[i] = bytes[i];
|
||||
}
|
||||
return result;
|
||||
// Since a Byte[] can contain nulls but a byte[] can't, we have to serialize/deserialize the content
|
||||
return (Byte[]) SerializationHelper.deserialize( bytes );
|
||||
}
|
||||
|
||||
private byte[] unwrapBytes(Byte[] bytes) {
|
||||
if ( bytes == null ) {
|
||||
return null;
|
||||
}
|
||||
final byte[] result = new byte[bytes.length];
|
||||
for ( int i = 0; i < bytes.length; i++ ) {
|
||||
result[i] = bytes[i];
|
||||
}
|
||||
return result;
|
||||
|
||||
// Since a Byte[] can contain nulls but a byte[] can't, we have to serialize/deserialize the content
|
||||
return SerializationHelper.serialize( bytes );
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,7 +22,6 @@ import org.hibernate.collection.spi.CollectionSemantics;
|
|||
import org.hibernate.dialect.Dialect;
|
||||
import org.hibernate.engine.jdbc.BinaryStream;
|
||||
import org.hibernate.engine.jdbc.internal.BinaryStreamImpl;
|
||||
import org.hibernate.engine.jdbc.spi.JdbcServices;
|
||||
import org.hibernate.internal.util.SerializationHelper;
|
||||
import org.hibernate.internal.util.collections.CollectionHelper;
|
||||
import org.hibernate.metamodel.CollectionClassification;
|
||||
|
@ -30,7 +29,10 @@ import org.hibernate.tool.schema.extract.spi.ColumnTypeInformation;
|
|||
import org.hibernate.type.BasicCollectionType;
|
||||
import org.hibernate.type.BasicPluralType;
|
||||
import org.hibernate.type.BasicType;
|
||||
import org.hibernate.type.descriptor.converter.internal.CollectionConverter;
|
||||
import org.hibernate.type.ConvertedBasicCollectionType;
|
||||
import org.hibernate.type.descriptor.WrapperOptions;
|
||||
import org.hibernate.type.descriptor.converter.spi.BasicValueConverter;
|
||||
import org.hibernate.type.descriptor.java.AbstractJavaType;
|
||||
import org.hibernate.type.descriptor.java.BasicPluralJavaType;
|
||||
import org.hibernate.type.descriptor.java.JavaType;
|
||||
|
@ -110,22 +112,47 @@ public class BasicCollectionJavaType<C extends Collection<E>, E> extends Abstrac
|
|||
// Register the collection type as that will be resolved in the next step
|
||||
typeConfiguration.getJavaTypeRegistry().addDescriptor( collectionJavaType );
|
||||
}
|
||||
return typeConfiguration.standardBasicTypeForJavaType(
|
||||
collectionJavaType.getJavaType(),
|
||||
javaType -> {
|
||||
JdbcType arrayJdbcType = typeConfiguration.getJdbcTypeRegistry().getDescriptor( Types.ARRAY );
|
||||
if ( arrayJdbcType instanceof ArrayJdbcType ) {
|
||||
arrayJdbcType = ( (ArrayJdbcType) arrayJdbcType ).resolveType(
|
||||
typeConfiguration,
|
||||
dialect,
|
||||
elementType,
|
||||
columnTypeInformation
|
||||
);
|
||||
final BasicValueConverter<E, ?> valueConverter = elementType.getValueConverter();
|
||||
if ( valueConverter == null ) {
|
||||
return typeConfiguration.standardBasicTypeForJavaType(
|
||||
collectionJavaType.getJavaType(),
|
||||
javaType -> {
|
||||
JdbcType arrayJdbcType = typeConfiguration.getJdbcTypeRegistry().getDescriptor( Types.ARRAY );
|
||||
if ( arrayJdbcType instanceof ArrayJdbcType ) {
|
||||
arrayJdbcType = ( (ArrayJdbcType) arrayJdbcType ).resolveType(
|
||||
typeConfiguration,
|
||||
dialect,
|
||||
elementType,
|
||||
columnTypeInformation
|
||||
);
|
||||
}
|
||||
//noinspection unchecked,rawtypes
|
||||
return new BasicCollectionType( elementType, arrayJdbcType, collectionJavaType );
|
||||
}
|
||||
//noinspection unchecked,rawtypes
|
||||
return new BasicCollectionType( elementType, arrayJdbcType, collectionJavaType );
|
||||
}
|
||||
);
|
||||
);
|
||||
}
|
||||
else {
|
||||
final JavaType<Object> relationalJavaType = typeConfiguration.getJavaTypeRegistry().resolveDescriptor(
|
||||
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
|
||||
return new ConvertedBasicCollectionType<>(
|
||||
elementType,
|
||||
arrayJdbcType,
|
||||
collectionJavaType,
|
||||
new CollectionConverter( valueConverter, collectionJavaType, relationalJavaType )
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -24,6 +24,8 @@ import org.hibernate.type.descriptor.ValueBinder;
|
|||
import org.hibernate.type.descriptor.ValueExtractor;
|
||||
import org.hibernate.type.descriptor.WrapperOptions;
|
||||
import org.hibernate.type.descriptor.java.BasicPluralJavaType;
|
||||
import org.hibernate.type.descriptor.java.ByteArrayJavaType;
|
||||
import org.hibernate.type.descriptor.java.ByteJavaType;
|
||||
import org.hibernate.type.descriptor.java.JavaType;
|
||||
import org.hibernate.type.descriptor.jdbc.internal.JdbcLiteralFormatterArray;
|
||||
import org.hibernate.type.spi.TypeConfiguration;
|
||||
|
@ -86,9 +88,17 @@ public class ArrayJdbcType implements JdbcType {
|
|||
|
||||
@Override
|
||||
public <T> JdbcLiteralFormatter<T> getJdbcLiteralFormatter(JavaType<T> javaTypeDescriptor) {
|
||||
//noinspection unchecked
|
||||
final BasicPluralJavaType<T> basicPluralJavaType = (BasicPluralJavaType<T>) javaTypeDescriptor;
|
||||
final JdbcLiteralFormatter<T> elementFormatter = elementJdbcType.getJdbcLiteralFormatter( basicPluralJavaType.getElementJavaType() );
|
||||
final JavaType<T> elementJavaType;
|
||||
if ( javaTypeDescriptor instanceof ByteArrayJavaType ) {
|
||||
// Special handling needed for Byte[], because that would conflict with the VARBINARY mapping
|
||||
//noinspection unchecked
|
||||
elementJavaType = (JavaType<T>) ByteJavaType.INSTANCE;
|
||||
}
|
||||
else {
|
||||
//noinspection unchecked
|
||||
elementJavaType = ( (BasicPluralJavaType<T>) javaTypeDescriptor ).getElementJavaType();
|
||||
}
|
||||
final JdbcLiteralFormatter<T> elementFormatter = elementJdbcType.getJdbcLiteralFormatter( elementJavaType );
|
||||
return new JdbcLiteralFormatterArray<>( javaTypeDescriptor, elementFormatter );
|
||||
}
|
||||
|
||||
|
@ -99,20 +109,18 @@ public class ArrayJdbcType implements JdbcType {
|
|||
|
||||
@Override
|
||||
public <X> ValueBinder<X> getBinder(final JavaType<X> javaTypeDescriptor) {
|
||||
//noinspection unchecked
|
||||
final BasicPluralJavaType<X> containerJavaType = (BasicPluralJavaType<X>) javaTypeDescriptor;
|
||||
return new BasicBinder<X>( javaTypeDescriptor, this ) {
|
||||
|
||||
@Override
|
||||
protected void doBind(PreparedStatement st, X value, int index, WrapperOptions options) throws SQLException {
|
||||
final java.sql.Array arr = getArray( value, containerJavaType, options );
|
||||
final java.sql.Array arr = getArray( value, options );
|
||||
st.setArray( index, arr );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doBind(CallableStatement st, X value, String name, WrapperOptions options)
|
||||
throws SQLException {
|
||||
final java.sql.Array arr = getArray( value, containerJavaType, options );
|
||||
final java.sql.Array arr = getArray( value, options );
|
||||
try {
|
||||
st.setObject( name, arr, java.sql.Types.ARRAY );
|
||||
}
|
||||
|
@ -123,9 +131,9 @@ public class ArrayJdbcType implements JdbcType {
|
|||
|
||||
private java.sql.Array getArray(
|
||||
X value,
|
||||
BasicPluralJavaType<X> containerJavaType,
|
||||
WrapperOptions options) throws SQLException {
|
||||
final TypeConfiguration typeConfiguration = options.getSessionFactory().getTypeConfiguration();
|
||||
final JdbcType elementJdbcType = ( (ArrayJdbcType) getJdbcType() ).getElementJdbcType();
|
||||
final JdbcType underlyingJdbcType = typeConfiguration.getJdbcTypeRegistry()
|
||||
.getDescriptor( elementJdbcType.getDefaultSqlTypeCode() );
|
||||
final Class<?> preferredJavaTypeClass = elementJdbcType.getPreferredJavaTypeClass( options );
|
||||
|
@ -145,15 +153,31 @@ public class ArrayJdbcType implements JdbcType {
|
|||
elementJdbcJavaTypeClass,
|
||||
0
|
||||
).getClass();
|
||||
final Object[] objects = javaTypeDescriptor.unwrap( value, arrayClass, options );
|
||||
final Object[] objects = getJavaType().unwrap( value, arrayClass, options );
|
||||
|
||||
final SharedSessionContractImplementor session = options.getSession();
|
||||
// TODO: ideally, we would have the actual size or the actual type/column accessible
|
||||
// this is something that we would need for supporting composite types anyway
|
||||
final JavaType<X> elementJavaType;
|
||||
if ( getJavaType() instanceof ByteArrayJavaType ) {
|
||||
// Special handling needed for Byte[], because that would conflict with the VARBINARY mapping
|
||||
//noinspection unchecked
|
||||
elementJavaType = (JavaType<X>) ByteJavaType.INSTANCE;
|
||||
}
|
||||
else {
|
||||
//noinspection unchecked
|
||||
elementJavaType = ( (BasicPluralJavaType<X>) getJavaType() ).getElementJavaType();
|
||||
}
|
||||
final Size size = session.getJdbcServices()
|
||||
.getDialect()
|
||||
.getSizeStrategy()
|
||||
.resolveSize( elementJdbcType, containerJavaType.getElementJavaType(), null, null, null );
|
||||
.resolveSize(
|
||||
elementJdbcType,
|
||||
elementJavaType,
|
||||
null,
|
||||
null,
|
||||
null
|
||||
);
|
||||
String typeName = session.getTypeConfiguration()
|
||||
.getDdlTypeRegistry()
|
||||
.getDescriptor( elementJdbcType.getDdlTypeCode() )
|
||||
|
|
|
@ -0,0 +1,54 @@
|
|||
/*
|
||||
* 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 java.sql.Types;
|
||||
|
||||
import org.hibernate.type.descriptor.WrapperOptions;
|
||||
import org.hibernate.type.descriptor.java.JavaType;
|
||||
import org.hibernate.type.spi.TypeConfiguration;
|
||||
|
||||
/**
|
||||
* Descriptor for {@link Types#TINYINT TINYINT} handling, when the {@link Types#SMALLINT SMALLINT} DDL type code is used.
|
||||
* This type extends {@link SmallIntJdbcType}, because on the JDBC side we must bind {@link Short} instead of {@link Byte},
|
||||
* because it is not specified whether the conversion from {@link Byte} to {@link Short} is signed or unsigned,
|
||||
* and we need the conversion to be signed, which is properly handled by the {@link org.hibernate.type.descriptor.java.JavaType#unwrap(Object, Class, WrapperOptions)} implementations.
|
||||
*/
|
||||
public class TinyIntAsSmallIntJdbcType extends SmallIntJdbcType {
|
||||
public static final TinyIntAsSmallIntJdbcType INSTANCE = new TinyIntAsSmallIntJdbcType();
|
||||
|
||||
public TinyIntAsSmallIntJdbcType() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getJdbcTypeCode() {
|
||||
return Types.TINYINT;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getDdlTypeCode() {
|
||||
return Types.SMALLINT;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getFriendlyName() {
|
||||
return "TINYINT";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "TinyIntAsSmallIntTypeDescriptor";
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> JavaType<T> getJdbcRecommendedJavaTypeMapping(
|
||||
Integer length,
|
||||
Integer scale,
|
||||
TypeConfiguration typeConfiguration) {
|
||||
return typeConfiguration.getJavaTypeRegistry().getDescriptor( Byte.class );
|
||||
}
|
||||
}
|
|
@ -59,7 +59,7 @@ public class EnumResolutionTests {
|
|||
verifyEnumResolution(
|
||||
entityBinding.getProperty( "rawEnum" ),
|
||||
Types.TINYINT,
|
||||
Integer.class,
|
||||
Byte.class,
|
||||
OrdinalEnumValueConverter.class,
|
||||
true
|
||||
);
|
||||
|
@ -74,7 +74,7 @@ public class EnumResolutionTests {
|
|||
verifyEnumResolution(
|
||||
entityBinding.getProperty( "unspecifiedMappingEnum" ),
|
||||
Types.TINYINT,
|
||||
Integer.class,
|
||||
Byte.class,
|
||||
OrdinalEnumValueConverter.class,
|
||||
true
|
||||
);
|
||||
|
@ -89,7 +89,7 @@ public class EnumResolutionTests {
|
|||
verifyEnumResolution(
|
||||
entityBinding.getProperty( "ordinalEnum" ),
|
||||
Types.TINYINT,
|
||||
Integer.class,
|
||||
Byte.class,
|
||||
OrdinalEnumValueConverter.class,
|
||||
true
|
||||
);
|
||||
|
@ -139,7 +139,7 @@ public class EnumResolutionTests {
|
|||
verifyEnumResolution(
|
||||
entityBinding.getProperty( "explicitEnum" ),
|
||||
Types.SMALLINT,
|
||||
Integer.class,
|
||||
Short.class,
|
||||
OrdinalEnumValueConverter.class,
|
||||
true
|
||||
);
|
||||
|
|
|
@ -8,17 +8,6 @@ package org.hibernate.orm.test.mapping;
|
|||
|
||||
import java.sql.Statement;
|
||||
import java.sql.Types;
|
||||
import jakarta.persistence.AttributeConverter;
|
||||
import jakarta.persistence.Column;
|
||||
import jakarta.persistence.Convert;
|
||||
import jakarta.persistence.Embeddable;
|
||||
import jakarta.persistence.Embedded;
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.EnumType;
|
||||
import jakarta.persistence.Enumerated;
|
||||
import jakarta.persistence.Id;
|
||||
import jakarta.persistence.ManyToOne;
|
||||
import jakarta.persistence.Table;
|
||||
|
||||
import org.hibernate.metamodel.mapping.EntityIdentifierMapping;
|
||||
import org.hibernate.metamodel.mapping.ModelPart;
|
||||
|
@ -42,12 +31,25 @@ import org.junit.jupiter.api.AfterEach;
|
|||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import jakarta.persistence.AttributeConverter;
|
||||
import jakarta.persistence.Column;
|
||||
import jakarta.persistence.Convert;
|
||||
import jakarta.persistence.Embeddable;
|
||||
import jakarta.persistence.Embedded;
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.EnumType;
|
||||
import jakarta.persistence.Enumerated;
|
||||
import jakarta.persistence.Id;
|
||||
import jakarta.persistence.ManyToOne;
|
||||
import jakarta.persistence.Table;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.equalTo;
|
||||
import static org.hamcrest.CoreMatchers.instanceOf;
|
||||
import static org.hamcrest.CoreMatchers.is;
|
||||
import static org.hamcrest.CoreMatchers.notNullValue;
|
||||
import static org.hamcrest.CoreMatchers.sameInstance;
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.hamcrest.Matchers.isOneOf;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
|
@ -98,7 +100,10 @@ public class SmokeTests {
|
|||
valueConverter.getDomainJavaType().getJavaTypeClass(),
|
||||
equalTo( genderAttrMapping.getJavaType().getJavaTypeClass() )
|
||||
);
|
||||
assertThat( valueConverter.getRelationalJavaType().getJavaTypeClass(), equalTo( Integer.class ) );
|
||||
assertThat(
|
||||
valueConverter.getRelationalJavaType().getJavaTypeClass(),
|
||||
isOneOf( Byte.class, Short.class, Integer.class )
|
||||
);
|
||||
|
||||
assertThat(
|
||||
jdbcTypeRegistry.getDescriptor( valueConverter.getJdbcTypeCode() ),
|
||||
|
|
|
@ -38,12 +38,7 @@ import org.hibernate.sql.results.graph.DomainResultAssembler;
|
|||
import org.hibernate.sql.results.graph.basic.BasicResult;
|
||||
import org.hibernate.sql.results.graph.basic.BasicResultAssembler;
|
||||
import org.hibernate.sql.results.internal.SqlSelectionImpl;
|
||||
import org.hibernate.type.CustomType;
|
||||
import org.hibernate.type.EnumType;
|
||||
import org.hibernate.type.descriptor.jdbc.JdbcType;
|
||||
import org.hibernate.type.descriptor.jdbc.spi.JdbcTypeRegistry;
|
||||
|
||||
import org.hibernate.testing.hamcrest.AssignableMatcher;
|
||||
import org.hibernate.testing.orm.junit.DomainModel;
|
||||
import org.hibernate.testing.orm.junit.ServiceRegistry;
|
||||
import org.hibernate.testing.orm.junit.SessionFactory;
|
||||
|
@ -56,6 +51,7 @@ import static org.hamcrest.CoreMatchers.instanceOf;
|
|||
import static org.hamcrest.CoreMatchers.is;
|
||||
import static org.hamcrest.CoreMatchers.notNullValue;
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.hamcrest.Matchers.isOneOf;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
|
@ -170,7 +166,10 @@ public class SmokeTests {
|
|||
assertThat( selectedExpressible.getJdbcType().isInteger(), is( true ) );
|
||||
|
||||
final EnumValueConverter<?, ?> enumConverter = (EnumValueConverter<?, ?>) selectedExpressible.getValueConverter();
|
||||
assertThat( enumConverter.getRelationalJavaType().getJavaTypeClass(), AssignableMatcher.assignableTo( Integer.class ) );
|
||||
assertThat(
|
||||
enumConverter.getRelationalJavaType().getJavaTypeClass(),
|
||||
isOneOf( Byte.class, Short.class, Integer.class )
|
||||
);
|
||||
|
||||
assertThat( sqlAst.getDomainResultDescriptors().size(), is( 1 ) );
|
||||
final DomainResult<?> domainResult = sqlAst.getDomainResultDescriptors().get( 0 );
|
||||
|
|
|
@ -14,8 +14,6 @@ import org.hibernate.dialect.MySQLDialect;
|
|||
import org.hibernate.dialect.OracleDialect;
|
||||
import org.hibernate.dialect.SybaseASEDialect;
|
||||
import org.hibernate.internal.util.SerializationHelper;
|
||||
import org.hibernate.type.SqlTypes;
|
||||
import org.hibernate.type.descriptor.sql.spi.DdlTypeRegistry;
|
||||
|
||||
import jakarta.persistence.Column;
|
||||
import jakarta.persistence.Entity;
|
||||
|
@ -41,7 +39,6 @@ import static org.junit.Assert.assertThat;
|
|||
* @author Christian Beikov
|
||||
*/
|
||||
@SkipForDialect(value = SybaseASEDialect.class, comment = "Sybase or the driver are trimming trailing zeros in byte arrays")
|
||||
@SkipForDialect( value = OracleDialect.class, jiraKey = "HHH-16333", comment = "converters not handled properly" )
|
||||
public class EnumArrayTest extends BaseNonConfigCoreFunctionalTestCase {
|
||||
|
||||
@Override
|
||||
|
@ -135,12 +132,13 @@ public class EnumArrayTest extends BaseNonConfigCoreFunctionalTestCase {
|
|||
}
|
||||
|
||||
private Object nativeEnumArray(MyEnum... enums) {
|
||||
final DdlTypeRegistry ddlTypeRegistry = sessionFactory().getTypeConfiguration().getDdlTypeRegistry();
|
||||
final String tinyintType = ddlTypeRegistry.getDescriptor( SqlTypes.TINYINT ).getRawTypeName();
|
||||
final String smallintType = ddlTypeRegistry.getDescriptor( SqlTypes.SMALLINT ).getRawTypeName();
|
||||
// We have to bind a Short[] if the DDL type is smallint to align with the Hibernate mapping,
|
||||
// but also if the dialect supports arrays natively, because then a Short[] can be coerced to a Byte[]
|
||||
if ( tinyintType.equals( smallintType ) || getDialect().supportsStandardArrays() ) {
|
||||
// We also have to pass a Short[] for Oracle because that serializes to XML by default
|
||||
if ( getDialect().supportsStandardArrays() || getDialect() instanceof OracleDialect ) {
|
||||
// For native queries we must bind a Short[] instead of Byte[] even if we can use the "tinyint array" DDL type.
|
||||
// This is because the JavaType we have registered for Byte[] does not implement BasicPluralJavaType.
|
||||
// We can't make it implement that though, because that would be backwards incompatible,
|
||||
// leading to Byte[] uses in the domain being treated as "tinyint array" or "smallint array" instead of varbinary.
|
||||
// Luckily, JDBC drivers that support standard arrays are capable to coerce a Short[] to Byte[]
|
||||
final Short[] array = new Short[enums.length];
|
||||
for ( int i = 0; i < enums.length; i++ ) {
|
||||
array[i] = enums[i] == null ? null : (short) enums[i].ordinal();
|
||||
|
|
|
@ -14,6 +14,23 @@ earlier versions, see any other pertinent migration guides as well.
|
|||
* link:{docsBase}/6.1/migration-guide/migration-guide.html[6.1 Migration guide]
|
||||
* link:{docsBase}/6.0/migration-guide/migration-guide.html[6.0 Migration guide]
|
||||
|
||||
[[data-format-changes]]
|
||||
== Data format changes
|
||||
|
||||
[[data-format-wrapper-byte-array]]
|
||||
=== Byte[] data format changes
|
||||
|
||||
Prior to Hibernate 6.2, a `Byte[]` in the domain model was always just blindly converted to a `byte[]`,
|
||||
possibly running into a `NullPointerException` if the `Byte[]` contains a `null` array element.
|
||||
|
||||
To fix this, a `Byte[]` is now serialized with Java serialization to a `byte[]`, which allows handling nulls better.
|
||||
This change is necessary to properly support plural basic types where the element type maps to the `Byte` Java type,
|
||||
i.e. an array or collection of `Enum`.
|
||||
|
||||
Since the use of `Byte[]` in a domain model did not make sense so far because null elements were impossible,
|
||||
it is expected that most domain models were already using `byte[]`, so the breaking change was considered to be ok.
|
||||
|
||||
Domain models that really used a `Byte[]` but never stored a `null`, must be migrated to `byte[]` now.
|
||||
|
||||
[[ddl-changes]]
|
||||
== DDL type changes
|
||||
|
|
Loading…
Reference in New Issue