Add support for specifying the SqlTypes field name when a type code is expected

This commit is contained in:
Christian Beikov 2022-03-25 22:16:58 +01:00
parent e1742ac3ac
commit b4a1b149fb
5 changed files with 63 additions and 11 deletions

View File

@ -382,9 +382,11 @@ This setting applies to Oracle Dialect only, and it specifies whether `byte[]` o
`*hibernate.type.preferred_boolean_jdbc_type_code*` (e.g. `-7` for `java.sql.Types.BIT`)::
Global setting identifying the preferred JDBC type code for storing boolean values. The fallback is to ask the Dialect.
Can also specify the name of the constant in `org.hibernate.type.SqlTypes` instead.
`*hibernate.type.preferred_duration_jdbc_type_code*` (e.g. `2` for `java.sql.Types.NUMERIC` or `3100` for `org.hibernate.types.SqlTypes.INTERVAL_SECOND` (default value))::
Global setting identifying the preferred JDBC type code for storing duration values.
Can also specify the name of the constant in `org.hibernate.type.SqlTypes` instead.
==== Bean Validation options
`*jakarta.persistence.validation.factory*` (e.g. `jakarta.validation.ValidationFactory` implementation)::

View File

@ -38,8 +38,7 @@ import static org.hamcrest.Matchers.is;
*/
@DomainModel(annotatedClasses = DurationMappingLegacyTests.EntityWithDuration.class)
@SessionFactory
// 2 stands for the type code Types.NUMERIC
@ServiceRegistry(settings = @Setting(name = AvailableSettings.PREFERRED_DURATION_JDBC_TYPE_CODE, value = "2"))
@ServiceRegistry(settings = @Setting(name = AvailableSettings.PREFERRED_DURATION_JDBC_TYPE_CODE, value = "NUMERIC"))
public class DurationMappingLegacyTests {
@Test

View File

@ -2479,6 +2479,8 @@ public interface AvailableSettings {
* {@link org.hibernate.dialect.Dialect#getPreferredSqlTypeCodeForBoolean()
* dialect-specific default type code} is used.
*
* Can also specify the name of the constant in {@link org.hibernate.type.SqlTypes} instead.
*
* @since 6.0
*/
String PREFERRED_BOOLEAN_JDBC_TYPE_CODE = "hibernate.type.preferred_boolean_jdbc_type_code";
@ -2487,6 +2489,8 @@ public interface AvailableSettings {
* Specifies the preferred JDBC type code for storing duration values. When no
* type code is explicitly specified, {@link org.hibernate.type.SqlTypes#INTERVAL_SECOND} is used.
*
* Can also specify the name of the constant in {@link org.hibernate.type.SqlTypes} instead.
*
* @since 6.0
*/
String PREFERRED_DURATION_JDBC_TYPE_CODE = "hibernate.type.preferred_duration_jdbc_type_code";

View File

@ -21,6 +21,7 @@ import org.hibernate.engine.jdbc.spi.JdbcServices;
import org.hibernate.internal.util.StringHelper;
import org.hibernate.internal.util.collections.ArrayHelper;
import org.hibernate.type.SqlTypes;
import org.hibernate.type.descriptor.JdbcTypeNameMapper;
/**
* Collection of helper methods for dealing with configuration settings.
@ -516,7 +517,7 @@ public final class ConfigurationHelper {
public static synchronized int getPreferredSqlTypeCodeForBoolean(StandardServiceRegistry serviceRegistry) {
final Integer typeCode = serviceRegistry.getService( ConfigurationService.class ).getSetting(
AvailableSettings.PREFERRED_BOOLEAN_JDBC_TYPE_CODE,
StandardConverters.INTEGER
TypeCodeConverter.INSTANCE
);
if ( typeCode != null ) {
return typeCode;
@ -532,9 +533,31 @@ public final class ConfigurationHelper {
public static synchronized int getPreferredSqlTypeCodeForDuration(StandardServiceRegistry serviceRegistry) {
return serviceRegistry.getService( ConfigurationService.class ).getSetting(
AvailableSettings.PREFERRED_DURATION_JDBC_TYPE_CODE,
StandardConverters.INTEGER,
TypeCodeConverter.INSTANCE,
SqlTypes.INTERVAL_SECOND
);
}
private static class TypeCodeConverter implements ConfigurationService.Converter<Integer> {
public static final TypeCodeConverter INSTANCE = new TypeCodeConverter();
@Override
public Integer convert(Object value) {
if ( value == null ) {
throw new IllegalArgumentException( "Null value passed to convert" );
}
if ( value instanceof Number ) {
return ( (Number) value ).intValue();
}
final String string = value.toString();
final Integer typeCode = JdbcTypeNameMapper.getTypeCode( string );
if ( typeCode != null ) {
return typeCode;
}
return Integer.parseInt( string );
}
}
}

View File

@ -26,16 +26,14 @@ import static org.hibernate.internal.CoreLogging.messageLogger;
public final class JdbcTypeNameMapper {
private static final CoreMessageLogger LOG = messageLogger( JdbcTypeNameMapper.class );
private static final Map<Integer,String> JDBC_TYPE_MAP = buildJdbcTypeMap( Types.class );
private static final Map<Integer,String> SQL_TYPE_MAP = buildJdbcTypeMap( SqlTypes.class );
private static final Map<Integer, String> JDBC_TYPE_MAP = buildJdbcTypeMap( Types.class );
private static final Map<Integer, String> SQL_TYPE_MAP = buildJdbcTypeMap( SqlTypes.class );
private static final Map<String, Integer> JDBC_TYPE_NAME_MAP = buildJdbcTypeNameMap( Types.class );
private static final Map<String, Integer> SQL_TYPE_NAME_MAP = buildJdbcTypeNameMap( SqlTypes.class );
private static Map<Integer, String> buildJdbcTypeMap(Class<?> typesClass) {
HashMap<Integer, String> map = new HashMap<>();
Field[] fields = typesClass.getFields();
if ( fields == null ) {
throw new HibernateException( "Unexpected problem extracting JDBC type mapping codes from java.sql.Types" );
}
for ( Field field : fields ) {
for ( Field field : typesClass.getFields() ) {
try {
final int code = field.getInt( null );
String old = map.put( code, field.getName() );
@ -50,6 +48,20 @@ public final class JdbcTypeNameMapper {
return Collections.unmodifiableMap( map );
}
private static Map<String, Integer> buildJdbcTypeNameMap(Class<?> typesClass) {
HashMap<String, Integer> map = new HashMap<>();
for ( Field field : typesClass.getFields() ) {
try {
final int code = field.getInt( null );
map.put( field.getName(), code );
}
catch ( IllegalAccessException e ) {
throw new HibernateException( "Unable to access JDBC type mapping [" + field.getName() + "]", e );
}
}
return Collections.unmodifiableMap( map );
}
/**
* Determine whether the given JDBC type code represents a standard JDBC type ("standard" being those defined on
* {@link java.sql.Types}).
@ -91,6 +103,18 @@ public final class JdbcTypeNameMapper {
return name;
}
/**
* Get the type code as in the static field names defined on {@link java.sql.Types}. If a type name is not
* recognized, <code>null</code> is returned.
*
* @param typeName The type name to find the code for.
*
* @return The type code.
*/
public static Integer getTypeCode(String typeName) {
return SQL_TYPE_NAME_MAP.get( typeName );
}
private JdbcTypeNameMapper() {
}