From 54ebeb0227e6f09a778a910e44d411911ee6fa01 Mon Sep 17 00:00:00 2001 From: Gavin King Date: Mon, 13 Jan 2025 11:39:00 +0100 Subject: [PATCH 1/4] HHH-19035 add UserType.isComparable() To allow a UserType to override the determination made by the JdbcType. --- .../produce/function/ArgumentTypesValidator.java | 5 ++++- ...eAdapter.java => UserTypeJdbcTypeAdapter.java} | 6 ++++++ .../java/org/hibernate/usertype/UserType.java | 15 +++++++++++++++ 3 files changed, 25 insertions(+), 1 deletion(-) rename hibernate-core/src/main/java/org/hibernate/type/internal/{UserTypeSqlTypeAdapter.java => UserTypeJdbcTypeAdapter.java} (97%) diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/produce/function/ArgumentTypesValidator.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/produce/function/ArgumentTypesValidator.java index e5b49539fc7d..902cfed6ab59 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/produce/function/ArgumentTypesValidator.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/produce/function/ArgumentTypesValidator.java @@ -203,7 +203,10 @@ private int validateArgument(int paramNumber, JdbcMappingContainer expressionTyp final int jdbcTypeCount = expressionType.getJdbcTypeCount(); for ( int i = 0; i < jdbcTypeCount; i++ ) { final JdbcMapping mapping = expressionType.getJdbcMapping( i ); - FunctionParameterType type = paramNumber < types.length ? types[paramNumber++] : types[types.length - 1]; + final FunctionParameterType type = + paramNumber < types.length + ? types[paramNumber++] + : types[types.length - 1]; if ( type != null ) { checkArgumentType( paramNumber, diff --git a/hibernate-core/src/main/java/org/hibernate/type/internal/UserTypeSqlTypeAdapter.java b/hibernate-core/src/main/java/org/hibernate/type/internal/UserTypeJdbcTypeAdapter.java similarity index 97% rename from hibernate-core/src/main/java/org/hibernate/type/internal/UserTypeSqlTypeAdapter.java rename to hibernate-core/src/main/java/org/hibernate/type/internal/UserTypeJdbcTypeAdapter.java index d5ed8c9f5658..f470d5a521aa 100644 --- a/hibernate-core/src/main/java/org/hibernate/type/internal/UserTypeSqlTypeAdapter.java +++ b/hibernate-core/src/main/java/org/hibernate/type/internal/UserTypeJdbcTypeAdapter.java @@ -53,6 +53,12 @@ public int getJdbcTypeCode() { return userType.getSqlType(); } + @Override + public boolean isComparable() { + final Boolean comparable = userType.isComparable(); + return comparable == null ? JdbcType.super.isComparable() : comparable; + } + @Override @SuppressWarnings("unchecked") public ValueBinder getBinder(JavaType javaType) { diff --git a/hibernate-core/src/main/java/org/hibernate/usertype/UserType.java b/hibernate-core/src/main/java/org/hibernate/usertype/UserType.java index d10910d9f821..8cafa6e4a295 100644 --- a/hibernate-core/src/main/java/org/hibernate/usertype/UserType.java +++ b/hibernate-core/src/main/java/org/hibernate/usertype/UserType.java @@ -524,4 +524,19 @@ default JdbcType getJdbcType(TypeConfiguration typeConfiguration) { default BasicValueConverter getValueConverter() { return null; } + + /** + * Is this a comparable type in HQL? A type is comparable if it may be + * used with comparison operators like {@code >=}, and with {@code max()} + * and {@code min()}. + * + * @return {@code null} by default to indicate that the assigned + * {@code JdbcType} should decide + * + * @since 7.0 + */ + @Incubating + default Boolean isComparable() { + return null; + } } From 5c2809a3e1922e12b9f172bdaaedb395f2887349 Mon Sep 17 00:00:00 2001 From: Gavin King Date: Mon, 13 Jan 2025 11:39:57 +0100 Subject: [PATCH 2/4] misc code cleanups around UserTypes --- .../java/org/hibernate/type/CustomType.java | 139 ++++++++---------- .../descriptor/java/DurationJavaType.java | 20 ++- .../type/descriptor/jdbc/JdbcType.java | 65 +++----- .../internal/UserTypeJavaTypeWrapper.java | 75 +++++----- .../internal/UserTypeJdbcTypeAdapter.java | 58 ++++---- 5 files changed, 154 insertions(+), 203 deletions(-) diff --git a/hibernate-core/src/main/java/org/hibernate/type/CustomType.java b/hibernate-core/src/main/java/org/hibernate/type/CustomType.java index 795434f0b400..4a2c60959e58 100644 --- a/hibernate-core/src/main/java/org/hibernate/type/CustomType.java +++ b/hibernate-core/src/main/java/org/hibernate/type/CustomType.java @@ -17,7 +17,6 @@ import org.hibernate.engine.internal.CacheHelper; import org.hibernate.engine.spi.SessionFactoryImplementor; import org.hibernate.engine.spi.SharedSessionContractImplementor; -import org.hibernate.internal.util.collections.ArrayHelper; import org.hibernate.type.descriptor.converter.spi.BasicValueConverter; import org.hibernate.type.descriptor.ValueBinder; import org.hibernate.type.descriptor.ValueExtractor; @@ -26,7 +25,7 @@ import org.hibernate.type.descriptor.jdbc.JdbcLiteralFormatter; import org.hibernate.type.descriptor.jdbc.JdbcType; import org.hibernate.type.internal.UserTypeJavaTypeWrapper; -import org.hibernate.type.internal.UserTypeSqlTypeAdapter; +import org.hibernate.type.internal.UserTypeJdbcTypeAdapter; import org.hibernate.type.internal.UserTypeVersionJavaTypeWrapper; import org.hibernate.type.spi.TypeConfiguration; import org.hibernate.usertype.EnhancedUserType; @@ -34,6 +33,8 @@ import org.hibernate.usertype.UserType; import org.hibernate.usertype.UserVersionType; +import static org.hibernate.internal.util.collections.ArrayHelper.EMPTY_STRING_ARRAY; + /** * Adapts {@link UserType} to the generic {@link Type} interface, in order * to isolate user code from changes in the internal Type contracts. @@ -63,36 +64,22 @@ public class CustomType private final JdbcLiteralFormatter jdbcLiteralFormatter; public CustomType(UserType userType, TypeConfiguration typeConfiguration) throws MappingException { - this( userType, ArrayHelper.EMPTY_STRING_ARRAY, typeConfiguration ); + this( userType, EMPTY_STRING_ARRAY, typeConfiguration ); } - public CustomType(UserType userType, String[] registrationKeys, TypeConfiguration typeConfiguration) - throws MappingException { + public CustomType(UserType userType, String[] registrationKeys, TypeConfiguration typeConfiguration) { this.userType = userType; name = userType.getClass().getName(); - if ( userType instanceof JavaType ) { - //noinspection unchecked - mappedJavaType = (JavaType) userType; - } - else if ( userType instanceof JavaTypedExpressible) { - //noinspection unchecked - mappedJavaType = ( (JavaTypedExpressible) userType ).getExpressibleJavaType(); - } - else if ( userType instanceof UserVersionType ) { - mappedJavaType = new UserTypeVersionJavaTypeWrapper<>( (UserVersionType) userType ); - } - else { - mappedJavaType = new UserTypeJavaTypeWrapper<>( userType ); - } + mappedJavaType = getMappedJavaType( userType ); - final BasicValueConverter valueConverter = userType.getValueConverter(); - if ( valueConverter != null ) { + final BasicValueConverter converter = userType.getValueConverter(); + if ( converter != null ) { // When an explicit value converter is given, // we configure the custom type to use that instead of adapters that delegate to UserType. // This is necessary to support selecting a column with multiple domain type representations. jdbcType = userType.getJdbcType( typeConfiguration ); - jdbcJavaType = valueConverter.getRelationalJavaType(); + jdbcJavaType = converter.getRelationalJavaType(); //noinspection unchecked valueExtractor = (ValueExtractor) jdbcType.getExtractor( jdbcJavaType ); //noinspection unchecked @@ -102,18 +89,34 @@ else if ( userType instanceof UserVersionType ) { } else { // create a JdbcType adapter that uses the UserType binder/extract handling - jdbcType = new UserTypeSqlTypeAdapter<>( userType, mappedJavaType, typeConfiguration ); + jdbcType = new UserTypeJdbcTypeAdapter<>( userType, mappedJavaType ); jdbcJavaType = jdbcType.getJdbcRecommendedJavaTypeMapping( null, null, typeConfiguration ); valueExtractor = jdbcType.getExtractor( mappedJavaType ); valueBinder = jdbcType.getBinder( mappedJavaType ); - jdbcLiteralFormatter = userType instanceof EnhancedUserType - ? jdbcType.getJdbcLiteralFormatter( mappedJavaType ) - : null; + jdbcLiteralFormatter = + userType instanceof EnhancedUserType ? jdbcType.getJdbcLiteralFormatter( mappedJavaType ) : null; } this.registrationKeys = registrationKeys; } + private JavaType getMappedJavaType(UserType userType) { + if ( userType instanceof JavaType ) { + //noinspection unchecked + return (JavaType) userType; + } + else if ( userType instanceof JavaTypedExpressible ) { + //noinspection unchecked + return ( (JavaTypedExpressible) userType).getExpressibleJavaType(); + } + else if ( userType instanceof UserVersionType userVersionType ) { + return new UserTypeVersionJavaTypeWrapper<>( userVersionType ); + } + else { + return new UserTypeJavaTypeWrapper<>( userType ); + } + } + public UserType getUserType() { return userType; } @@ -176,13 +179,8 @@ public Object assemble(Serializable cached, SharedSessionContractImplementor ses // in which case we will try to use a converter for assembling, // or if that doesn't exist, simply use the relational value as is if ( assembled == null && cached != null ) { - final BasicValueConverter valueConverter = getUserType().getValueConverter(); - if ( valueConverter == null ) { - return cached; - } - else { - return valueConverter.toDomainValue( cached ); - } + final BasicValueConverter converter = getUserType().getValueConverter(); + return converter == null ? cached : converter.toDomainValue( cached ); } return assembled; } @@ -193,7 +191,7 @@ public Serializable disassemble(Object value, SharedSessionContractImplementor s } @Override - public Serializable disassemble(Object value, SessionFactoryImplementor sessionFactory) throws HibernateException { + public Serializable disassemble(Object value, SessionFactoryImplementor sessionFactory) { return disassembleForCache( value ); } @@ -204,27 +202,19 @@ private Serializable disassembleForCache(Object value) { // in which case we will try to use a converter for disassembling, // or if that doesn't exist, simply use the domain value as is if ( disassembled == null ){ - final BasicValueConverter valueConverter = getUserType().getValueConverter(); - if ( valueConverter == null ) { - return disassembled; - } - else { - return (Serializable) valueConverter.toRelationalValue( (J) value ); - } + final BasicValueConverter converter = getUserType().getValueConverter(); + return converter == null ? disassembled : (Serializable) converter.toRelationalValue( (J) value ); + } + else { + return disassembled; } - return disassembled; } @Override public Object disassemble(Object value, SharedSessionContractImplementor session) { // Use the value converter if available for conversion to the jdbc representation - final BasicValueConverter valueConverter = getUserType().getValueConverter(); - if ( valueConverter == null ) { - return value; - } - else { - return valueConverter.toRelationalValue( (J) value ); - } + final BasicValueConverter converter = getUserType().getValueConverter(); + return converter == null ? value : converter.toRelationalValue( (J) value ); } @Override @@ -240,12 +230,7 @@ public void addToCacheKey(MutableCacheKeyBuilder cacheKey, Object value, SharedS } else { cacheKey.addValue( disassembled ); - if ( value == null ) { - cacheKey.addHashCode( 0 ); - } - else { - cacheKey.addHashCode( getUserType().hashCode( (J) value ) ); - } + cacheKey.addHashCode( value == null ? 0 : getUserType().hashCode( (J) value ) ); } } @@ -255,7 +240,7 @@ public Object replace( Object target, SharedSessionContractImplementor session, Object owner, - Map copyCache) throws HibernateException { + Map copyCache) { return getUserType().replace( (J) original, (J) target, owner ); } @@ -302,8 +287,8 @@ public String toLoggableString(Object value, SessionFactoryImplementor factory) if ( value == null ) { return "null"; } - else if ( userType instanceof LoggableUserType ) { - return ( (LoggableUserType) userType ).toLoggableString( value, factory ); + else if ( userType instanceof LoggableUserType loggableUserType ) { + return loggableUserType.toLoggableString( value, factory ); } else if ( userType instanceof EnhancedUserType ) { return ( (EnhancedUserType) userType ).toString( value ); @@ -315,9 +300,9 @@ else if ( userType instanceof EnhancedUserType ) { @Override public boolean[] toColumnNullness(Object value, MappingContext mapping) { - boolean[] result = new boolean[ getColumnSpan(mapping) ]; + final boolean[] result = new boolean[ getColumnSpan(mapping) ]; if ( value != null ) { - Arrays.fill(result, true); + Arrays.fill( result, true ); } return result; } @@ -325,22 +310,22 @@ public boolean[] toColumnNullness(Object value, MappingContext mapping) { @Override public boolean isDirty(Object old, Object current, boolean[] checkable, SharedSessionContractImplementor session) throws HibernateException { - return checkable[0] && isDirty(old, current, session); + return checkable[0] && isDirty( old, current, session ); } @Override public boolean canDoSetting() { - if ( getUserType() instanceof ProcedureParameterNamedBinder ) { - return ((ProcedureParameterNamedBinder) getUserType() ).canDoSetting(); - } - return false; + return getUserType() instanceof ProcedureParameterNamedBinder procedureParameterNamedBinder + && procedureParameterNamedBinder.canDoSetting(); } @Override - public void nullSafeSet( - CallableStatement statement, J value, String name, SharedSessionContractImplementor session) throws SQLException { + public void nullSafeSet(CallableStatement statement, J value, String name, SharedSessionContractImplementor session) + throws SQLException { if ( canDoSetting() ) { - ((ProcedureParameterNamedBinder) getUserType() ).nullSafeSet( statement, value, name, session ); + //noinspection unchecked + ( (ProcedureParameterNamedBinder) getUserType() ) + .nullSafeSet( statement, value, name, session ); } else { throw new UnsupportedOperationException( @@ -351,17 +336,17 @@ public void nullSafeSet( @Override public boolean canDoExtraction() { - if ( getUserType() instanceof ProcedureParameterExtractionAware ) { - return ((ProcedureParameterExtractionAware) getUserType() ).canDoExtraction(); - } - return false; + return getUserType() instanceof ProcedureParameterExtractionAware procedureParameterExtractionAware + && procedureParameterExtractionAware.canDoExtraction(); } @Override - public J extract(CallableStatement statement, int startIndex, SharedSessionContractImplementor session) throws SQLException { + public J extract(CallableStatement statement, int startIndex, SharedSessionContractImplementor session) + throws SQLException { if ( canDoExtraction() ) { //noinspection unchecked - return ((ProcedureParameterExtractionAware) getUserType() ).extract( statement, startIndex, session ); + return ((ProcedureParameterExtractionAware) getUserType() ) + .extract( statement, startIndex, session ); } else { throw new UnsupportedOperationException( @@ -375,7 +360,8 @@ public J extract(CallableStatement statement, String paramName, SharedSessionCon throws SQLException { if ( canDoExtraction() ) { //noinspection unchecked - return ((ProcedureParameterExtractionAware) getUserType() ).extract( statement, paramName, session ); + return ((ProcedureParameterExtractionAware) getUserType() ) + .extract( statement, paramName, session ); } else { throw new UnsupportedOperationException( @@ -391,7 +377,8 @@ public int hashCode() { @Override public boolean equals(Object obj) { - return ( obj instanceof CustomType ) && getUserType().equals( ( (CustomType) obj ).getUserType() ); + return obj instanceof CustomType customType + && getUserType().equals( customType.getUserType() ); } @Override diff --git a/hibernate-core/src/main/java/org/hibernate/type/descriptor/java/DurationJavaType.java b/hibernate-core/src/main/java/org/hibernate/type/descriptor/java/DurationJavaType.java index c43ecec6819b..884fa5024327 100644 --- a/hibernate-core/src/main/java/org/hibernate/type/descriptor/java/DurationJavaType.java +++ b/hibernate-core/src/main/java/org/hibernate/type/descriptor/java/DurationJavaType.java @@ -60,10 +60,12 @@ public String toString(Duration value) { if ( value == null ) { return null; } - String seconds = String.valueOf( value.getSeconds() ); - String nanos = String.valueOf( value.getNano() ); - String zeros = StringHelper.repeat( '0', 9 - nanos.length() ); + else { + final String seconds = String.valueOf( value.getSeconds() ); + final String nanos = String.valueOf( value.getNano() ); + final String zeros = StringHelper.repeat( '0', 9 - nanos.length() ); return seconds + zeros + nanos; + } } @Override @@ -71,11 +73,13 @@ public Duration fromString(CharSequence string) { if ( string == null ) { return null; } - int cutoff = string.length() - 9; - return Duration.ofSeconds( - Long.parseLong( string.subSequence( 0, cutoff ).toString() ), - Long.parseLong( string.subSequence( cutoff, string.length() ).toString() ) - ); + else { + final int cutoff = string.length() - 9; + return Duration.ofSeconds( + Long.parseLong( string.subSequence( 0, cutoff ).toString() ), + Long.parseLong( string.subSequence( cutoff, string.length() ).toString() ) + ); + } } @Override diff --git a/hibernate-core/src/main/java/org/hibernate/type/descriptor/jdbc/JdbcType.java b/hibernate-core/src/main/java/org/hibernate/type/descriptor/jdbc/JdbcType.java index bff178a26cf5..58684a6da94c 100644 --- a/hibernate-core/src/main/java/org/hibernate/type/descriptor/jdbc/JdbcType.java +++ b/hibernate-core/src/main/java/org/hibernate/type/descriptor/jdbc/JdbcType.java @@ -312,53 +312,24 @@ default CastType getCastType() { } static CastType getCastType(int typeCode) { - switch ( typeCode ) { - case INTEGER: - case TINYINT: - case SMALLINT: - return CastType.INTEGER; - case BIGINT: - return CastType.LONG; - case FLOAT: - case REAL: - return CastType.FLOAT; - case DOUBLE: - return CastType.DOUBLE; - case CHAR: - case NCHAR: - case VARCHAR: - case NVARCHAR: - case LONGVARCHAR: - case LONGNVARCHAR: - return CastType.STRING; - case CLOB: - return CastType.CLOB; - case BOOLEAN: - return CastType.BOOLEAN; - case DECIMAL: - case NUMERIC: - return CastType.FIXED; - case DATE: - return CastType.DATE; - case TIME: - case TIME_UTC: - case TIME_WITH_TIMEZONE: - return CastType.TIME; - case TIMESTAMP: - return CastType.TIMESTAMP; - case TIMESTAMP_WITH_TIMEZONE: - return CastType.OFFSET_TIMESTAMP; - case JSON: - case JSON_ARRAY: - return CastType.JSON; - case SQLXML: - case XML_ARRAY: - return CastType.XML; - case NULL: - return CastType.NULL; - default: - return CastType.OTHER; - } + return switch ( typeCode ) { + case INTEGER, TINYINT, SMALLINT -> CastType.INTEGER; + case BIGINT -> CastType.LONG; + case FLOAT, REAL -> CastType.FLOAT; + case DOUBLE -> CastType.DOUBLE; + case CHAR, NCHAR, VARCHAR, NVARCHAR, LONGVARCHAR, LONGNVARCHAR -> CastType.STRING; + case CLOB -> CastType.CLOB; + case BOOLEAN -> CastType.BOOLEAN; + case DECIMAL, NUMERIC -> CastType.FIXED; + case DATE -> CastType.DATE; + case TIME, TIME_UTC, TIME_WITH_TIMEZONE -> CastType.TIME; + case TIMESTAMP -> CastType.TIMESTAMP; + case TIMESTAMP_WITH_TIMEZONE -> CastType.OFFSET_TIMESTAMP; + case JSON, JSON_ARRAY -> CastType.JSON; + case SQLXML, XML_ARRAY -> CastType.XML; + case NULL -> CastType.NULL; + default -> CastType.OTHER; + }; } /** diff --git a/hibernate-core/src/main/java/org/hibernate/type/internal/UserTypeJavaTypeWrapper.java b/hibernate-core/src/main/java/org/hibernate/type/internal/UserTypeJavaTypeWrapper.java index 28a8d69a9d4e..3ae395cf478e 100644 --- a/hibernate-core/src/main/java/org/hibernate/type/internal/UserTypeJavaTypeWrapper.java +++ b/hibernate-core/src/main/java/org/hibernate/type/internal/UserTypeJavaTypeWrapper.java @@ -67,10 +67,9 @@ public UserTypeJavaTypeWrapper(UserType userType) { } private int compare(J first, J second) { - if ( userType.equals( first, second ) ) { - return 0; - } - return Comparator.comparing( userType::hashCode ).compare( first, second ); + return userType.equals( first, second ) ? 0 + : Comparator.comparing( userType::hashCode ) + .compare( first, second ); } @Override @@ -115,40 +114,44 @@ public boolean areEqual(J one, J another) { @Override public J fromString(CharSequence string) { - if ( userType instanceof EnhancedUserType ) { - return ( (EnhancedUserType) userType ).fromStringValue( string ); + if ( userType instanceof EnhancedUserType enhancedUserType ) { + return enhancedUserType.fromStringValue( string ); } throw new UnsupportedOperationException( "No support for parsing UserType values from String: " + userType ); } @Override public String toString(J value) { - if ( userType.returnedClass().isInstance( value ) && userType instanceof EnhancedUserType ) { - return ( (EnhancedUserType) userType ).toString( value ); - } - return value == null ? "null" : value.toString(); + return userType.returnedClass().isInstance( value ) + && userType instanceof EnhancedUserType enhancedUserType + ? enhancedUserType.toString( value ) + : value == null ? "null" : value.toString(); } @Override public X unwrap(J value, Class type, WrapperOptions options) { - final BasicValueConverter valueConverter = userType.getValueConverter(); - if ( value != null && !type.isInstance( value ) && valueConverter != null ) { - final Object relationalValue = valueConverter.toRelationalValue( value ); - return valueConverter.getRelationalJavaType().unwrap( relationalValue, type, options ); + final BasicValueConverter converter = userType.getValueConverter(); + if ( value != null && !type.isInstance( value ) && converter != null ) { + final Object relationalValue = converter.toRelationalValue( value ); + return converter.getRelationalJavaType().unwrap( relationalValue, type, options ); + } + else { + //noinspection unchecked + return (X) value; } - //noinspection unchecked - return (X) value; } @Override public J wrap(X value, WrapperOptions options) { - final BasicValueConverter valueConverter = userType.getValueConverter(); - if ( value != null && !userType.returnedClass().isInstance( value ) && valueConverter != null ) { - final J domainValue = valueConverter.toDomainValue( value ); - return valueConverter.getDomainJavaType().wrap( domainValue, options ); + final BasicValueConverter converter = userType.getValueConverter(); + if ( value != null && !userType.returnedClass().isInstance( value ) && converter != null ) { + final J domainValue = converter.toDomainValue( value ); + return converter.getDomainJavaType().wrap( domainValue, options ); + } + else { + //noinspection unchecked + return (J) value; } - //noinspection unchecked - return (J) value; } @Override @@ -181,16 +184,11 @@ public Serializable disassemble(J value, SharedSessionContract session) { // in which case we will try to use a converter for disassembling, // or if that doesn't exist, simply use the domain value as is if ( disassembled == null && value != null ) { - final BasicValueConverter valueConverter = userType.getValueConverter(); - if ( valueConverter == null ) { - return (Serializable) value; - } - else { - return valueConverter.getRelationalJavaType().getMutabilityPlan().disassemble( - valueConverter.toRelationalValue( value ), - session - ); - } + final BasicValueConverter converter = userType.getValueConverter(); + return converter == null + ? (Serializable) value + : converter.getRelationalJavaType().getMutabilityPlan() + .disassemble( converter.toRelationalValue( value ), session ); } return disassembled; } @@ -203,15 +201,12 @@ public J assemble(Serializable cached, SharedSessionContract session) { // in which case we will try to use a converter for assembling, // or if that doesn't exist, simply use the relational value as is if ( assembled == null && cached != null ) { - final BasicValueConverter valueConverter = userType.getValueConverter(); - if ( valueConverter == null ) { - return (J) cached; - } - else { - return valueConverter.toDomainValue( cached ); - } + final BasicValueConverter converter = userType.getValueConverter(); + return converter == null ? (J) cached : converter.toDomainValue( cached ); + } + else { + return assembled; } - return assembled; } } } diff --git a/hibernate-core/src/main/java/org/hibernate/type/internal/UserTypeJdbcTypeAdapter.java b/hibernate-core/src/main/java/org/hibernate/type/internal/UserTypeJdbcTypeAdapter.java index f470d5a521aa..ef9991abbac7 100644 --- a/hibernate-core/src/main/java/org/hibernate/type/internal/UserTypeJdbcTypeAdapter.java +++ b/hibernate-core/src/main/java/org/hibernate/type/internal/UserTypeJdbcTypeAdapter.java @@ -28,19 +28,19 @@ * * @author Steve Ebersole */ -public class UserTypeSqlTypeAdapter implements JdbcType { +public class UserTypeJdbcTypeAdapter implements JdbcType { private final UserType userType; - private final JavaType jtd; + private final JavaType javaType; private final ValueExtractor valueExtractor; private final ValueBinder valueBinder; - public UserTypeSqlTypeAdapter(UserType userType, JavaType jtd, TypeConfiguration typeConfiguration) { + public UserTypeJdbcTypeAdapter(UserType userType, JavaType javaType) { this.userType = userType; - this.jtd = jtd; + this.javaType = javaType; - this.valueExtractor = new ValueExtractorImpl<>( userType, jtd ); - this.valueBinder = new ValueBinderImpl<>( userType, typeConfiguration ); + this.valueExtractor = new ValueExtractorImpl<>( userType ); + this.valueBinder = new ValueBinderImpl<>( userType ); } @Override @@ -63,7 +63,7 @@ public boolean isComparable() { @SuppressWarnings("unchecked") public ValueBinder getBinder(JavaType javaType) { assert javaType.getJavaTypeClass() == null - || jtd.getJavaTypeClass().isAssignableFrom( javaType.getJavaTypeClass() ); + || this.javaType.getJavaTypeClass().isAssignableFrom( javaType.getJavaTypeClass() ); return (ValueBinder) valueBinder; } @@ -71,7 +71,7 @@ public ValueBinder getBinder(JavaType javaType) { @SuppressWarnings("unchecked") public ValueExtractor getExtractor(JavaType javaType) { assert javaType.getJavaTypeClass() == null - || javaType.getJavaTypeClass().isAssignableFrom( jtd.getJavaTypeClass() ); + || javaType.getJavaTypeClass().isAssignableFrom( this.javaType.getJavaTypeClass() ); return (ValueExtractor) valueExtractor; } @@ -81,7 +81,7 @@ public JavaType getJdbcRecommendedJavaTypeMapping( Integer scale, TypeConfiguration typeConfiguration) { //noinspection unchecked - return (JavaType) jtd; + return (JavaType) javaType; } @Override @@ -97,11 +97,9 @@ public JdbcLiteralFormatter getJdbcLiteralFormatter(JavaType javaType) private static class ValueExtractorImpl implements ValueExtractor { private final UserType userType; - private final JavaType javaType; - public ValueExtractorImpl(UserType userType, JavaType javaType) { + public ValueExtractorImpl(UserType userType) { this.userType = userType; - this.javaType = javaType; } @Override @@ -138,28 +136,24 @@ public J extract(CallableStatement statement, String paramName, WrapperOptions o } private void logExtracted(int paramIndex, J extracted) { - if ( ! JdbcExtractingLogging.LOGGER.isTraceEnabled() ) { - return; - } - - if ( extracted == null ) { - JdbcExtractingLogging.logNullExtracted( paramIndex, userType.getSqlType() ); - } - else { - JdbcExtractingLogging.logExtracted( paramIndex, userType.getSqlType(), extracted ); + if ( JdbcExtractingLogging.LOGGER.isTraceEnabled() ) { + if ( extracted == null ) { + JdbcExtractingLogging.logNullExtracted( paramIndex, userType.getSqlType() ); + } + else { + JdbcExtractingLogging.logExtracted( paramIndex, userType.getSqlType(), extracted ); + } } } private void logExtracted(String paramName, J extracted) { - if ( ! JdbcExtractingLogging.LOGGER.isTraceEnabled() ) { - return; - } - - if ( extracted == null ) { - JdbcExtractingLogging.logNullExtracted( paramName, userType.getSqlType() ); - } - else { - JdbcExtractingLogging.logExtracted( paramName, userType.getSqlType(), extracted ); + if ( JdbcExtractingLogging.LOGGER.isTraceEnabled() ) { + if ( extracted == null ) { + JdbcExtractingLogging.logNullExtracted( paramName, userType.getSqlType() ); + } + else { + JdbcExtractingLogging.logExtracted( paramName, userType.getSqlType(), extracted ); + } } } } @@ -167,7 +161,7 @@ private void logExtracted(String paramName, J extracted) { private static class ValueBinderImpl implements ValueBinder { private final UserType userType; - public ValueBinderImpl(UserType userType, TypeConfiguration typeConfiguration) { + public ValueBinderImpl(UserType userType) { this.userType = userType; } @@ -185,7 +179,7 @@ public void bind(PreparedStatement st, J value, int index, WrapperOptions option } @Override - public void bind(CallableStatement st, J value, String name, WrapperOptions options) throws SQLException { + public void bind(CallableStatement st, J value, String name, WrapperOptions options) { throw new UnsupportedOperationException( "Using UserType for CallableStatement parameter binding not supported" ); } } From 835d270c33cdef8f6b3f6c00c5602c96117a77ce Mon Sep 17 00:00:00 2001 From: Gavin King Date: Mon, 13 Jan 2025 16:15:39 +0100 Subject: [PATCH 3/4] HHH-19035 mark two JdbcTypes as comparable --- .../hibernate/dialect/H2DurationIntervalSecondJdbcType.java | 5 +++++ .../hibernate/dialect/PostgreSQLIntervalSecondJdbcType.java | 5 +++++ 2 files changed, 10 insertions(+) diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/H2DurationIntervalSecondJdbcType.java b/hibernate-core/src/main/java/org/hibernate/dialect/H2DurationIntervalSecondJdbcType.java index e0e4e4699623..a8c0059f6a51 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/H2DurationIntervalSecondJdbcType.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/H2DurationIntervalSecondJdbcType.java @@ -43,6 +43,11 @@ public Class getPreferredJavaTypeClass(WrapperOptions options) { return Duration.class; } + @Override + public boolean isComparable() { + return true; + } + @Override public JdbcLiteralFormatter getJdbcLiteralFormatter(JavaType javaType) { return (appender, value, dialect, wrapperOptions) -> diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/PostgreSQLIntervalSecondJdbcType.java b/hibernate-core/src/main/java/org/hibernate/dialect/PostgreSQLIntervalSecondJdbcType.java index a96a720f7d72..f2962ad8b7d5 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/PostgreSQLIntervalSecondJdbcType.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/PostgreSQLIntervalSecondJdbcType.java @@ -43,6 +43,11 @@ public int getDefaultSqlTypeCode() { return SqlTypes.INTERVAL_SECOND; } + @Override + public boolean isComparable() { + return true; + } + @Override public Class getPreferredJavaTypeClass(WrapperOptions options) { return Duration.class; From 1dd4961e6d8f83de12132f197dd72d254a6da9dd Mon Sep 17 00:00:00 2001 From: Gavin King Date: Tue, 14 Jan 2025 14:24:14 +0100 Subject: [PATCH 4/4] fix ws to make spotless happy --- .../org/hibernate/type/internal/UserTypeJdbcTypeAdapter.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hibernate-core/src/main/java/org/hibernate/type/internal/UserTypeJdbcTypeAdapter.java b/hibernate-core/src/main/java/org/hibernate/type/internal/UserTypeJdbcTypeAdapter.java index ef9991abbac7..fb558ad8fd39 100644 --- a/hibernate-core/src/main/java/org/hibernate/type/internal/UserTypeJdbcTypeAdapter.java +++ b/hibernate-core/src/main/java/org/hibernate/type/internal/UserTypeJdbcTypeAdapter.java @@ -63,7 +63,7 @@ public boolean isComparable() { @SuppressWarnings("unchecked") public ValueBinder getBinder(JavaType javaType) { assert javaType.getJavaTypeClass() == null - || this.javaType.getJavaTypeClass().isAssignableFrom( javaType.getJavaTypeClass() ); + || this.javaType.getJavaTypeClass().isAssignableFrom( javaType.getJavaTypeClass() ); return (ValueBinder) valueBinder; }