proper logging and documentation for semi-deprecation of 'hibernate.dialect'

and code cleanup
This commit is contained in:
Gavin 2023-04-07 23:28:05 +02:00 committed by Gavin King
parent d8c300dcf1
commit e5545492cc
5 changed files with 298 additions and 210 deletions

View File

@ -475,6 +475,11 @@ public interface AvailableSettings {
* By default, Hibernate will attempt to automatically determine the dialect from the
* {@linkplain #URL JDBC URL} and JDBC metadata, so this setting is not usually necessary.
*
* @apiNote As of Hibernate 6, this property should not be explicitly specified,
* except when using a custom user-written implementation of {@code Dialect}.
* Instead, applications should allow Hibernate to select the {@code Dialect}
* automatically.
*
* @see org.hibernate.dialect.Dialect
*/
String DIALECT = "hibernate.dialect";

View File

@ -108,6 +108,9 @@ import static org.hibernate.type.descriptor.DateTimeUtils.appendAsTimestampWithN
* A {@linkplain Dialect SQL dialect} for DB2 for LUW (Linux, Unix, and Windows) version 10.5 and above.
*
* @author Gavin King
*
* @see DB2iDialect
* @see DB2zDialect
*/
public class DB2Dialect extends Dialect {

View File

@ -84,9 +84,9 @@ public class DialectFactoryImpl implements DialectFactory, ServiceRegistryAwareS
@Override
public Dialect buildDialect(Map<String,Object> configValues, DialectResolutionInfoSource resolutionInfoSource) throws HibernateException {
final Object dialectReference = configValues.get( AvailableSettings.DIALECT );
Dialect dialect = !isEmpty( dialectReference ) ?
constructDialect( dialectReference, resolutionInfoSource ) :
determineDialect( resolutionInfoSource );
Dialect dialect = !isEmpty( dialectReference )
? constructDialect( dialectReference, resolutionInfoSource )
: determineDialect( resolutionInfoSource );
logSelectedDialect( dialect );
return dialect;
}
@ -105,6 +105,9 @@ public class DialectFactoryImpl implements DialectFactory, ServiceRegistryAwareS
DEPRECATION_LOGGER.deprecatedDialect( dialectClass.getSimpleName() );
}
}
else if ( Dialect.class.getPackage() == dialectClass.getPackage() ) {
DEPRECATION_LOGGER.automaticDialect( dialectClass.getSimpleName() );
}
}
@SuppressWarnings("SimplifiableIfStatement")
@ -129,7 +132,7 @@ public class DialectFactoryImpl implements DialectFactory, ServiceRegistryAwareS
(dialectClass) -> {
try {
try {
if (resolutionInfoSource != null) {
if ( resolutionInfoSource != null ) {
return dialectClass.getConstructor( DialectResolutionInfo.class ).newInstance(
resolutionInfoSource.getDialectResolutionInfo()
);
@ -157,7 +160,7 @@ public class DialectFactoryImpl implements DialectFactory, ServiceRegistryAwareS
final String dialectFqn = dialectReference.toString();
if ( LEGACY_DIALECTS.contains( dialectFqn ) ) {
throw new StrategySelectionException(
"Couldn't load the dialect class for the `hibernate.dialect` [" + dialectFqn + "], " +
"Couldn't load the dialect class for the 'hibernate.dialect' [" + dialectFqn + "], " +
"because the application is missing a dependency on the hibernate-community-dialects module. " +
"Hibernate 6.2 dropped support for database versions that are unsupported by vendors " +
"and code for old versions was moved to the hibernate-community-dialects module. " +

View File

@ -20,14 +20,23 @@ import org.hibernate.engine.jdbc.dialect.spi.DialectFactory;
import org.hibernate.engine.jdbc.dialect.spi.DialectResolutionInfo;
import org.hibernate.engine.jdbc.env.spi.JdbcEnvironment;
import org.hibernate.internal.CoreMessageLogger;
import org.hibernate.internal.log.DeprecationLogger;
import org.hibernate.internal.util.NullnessHelper;
import org.hibernate.internal.util.StringHelper;
import org.hibernate.internal.util.config.ConfigurationHelper;
import org.hibernate.service.spi.ServiceRegistryImplementor;
import org.jboss.logging.Logger;
import static org.hibernate.cfg.AvailableSettings.DIALECT_DB_MAJOR_VERSION;
import static org.hibernate.cfg.AvailableSettings.DIALECT_DB_MINOR_VERSION;
import static org.hibernate.cfg.AvailableSettings.DIALECT_DB_NAME;
import static org.hibernate.cfg.AvailableSettings.JAKARTA_HBM2DDL_DB_MAJOR_VERSION;
import static org.hibernate.cfg.AvailableSettings.JAKARTA_HBM2DDL_DB_MINOR_VERSION;
import static org.hibernate.cfg.AvailableSettings.JAKARTA_HBM2DDL_DB_NAME;
import static org.hibernate.engine.jdbc.env.internal.JdbcEnvironmentImpl.isMultiTenancyEnabled;
import static org.hibernate.internal.log.DeprecationLogger.DEPRECATION_LOGGER;
import static org.hibernate.internal.util.NullnessHelper.coalesceSuppliedValues;
import static org.hibernate.internal.util.StringHelper.isNotEmpty;
import static org.hibernate.internal.util.config.ConfigurationHelper.getBoolean;
import static org.hibernate.internal.util.config.ConfigurationHelper.getInteger;
/**
* @author Steve Ebersole
*/
@ -48,89 +57,12 @@ public class JdbcEnvironmentInitiator implements StandardServiceInitiator<JdbcEn
public JdbcEnvironment initiateService(Map<String, Object> configurationValues, ServiceRegistryImplementor registry) {
final DialectFactory dialectFactory = registry.getService( DialectFactory.class );
// 'hibernate.temp.use_jdbc_metadata_defaults' is a temporary magic value.
// The need for it is intended to be alleviated with future development, thus it is
// not defined as an Environment constant...
//
// it is used to control whether we should consult the JDBC metadata to determine
// certain default values; it is useful to *not* do this when the database
// may not be available (mainly in tools usage).
final boolean useJdbcMetadata = ConfigurationHelper.getBoolean(
"hibernate.temp.use_jdbc_metadata_defaults",
configurationValues,
true
);
final String explicitDatabaseName = getExplicitDatabaseName( configurationValues );
Integer explicitDatabaseMajorVersion = getExplicitDatabaseMajorVersion( configurationValues );
Integer explicitDatabaseMinorVersion = getExplicitDatabaseMinorVersion( configurationValues );
String explicitDatabaseName = NullnessHelper.coalesceSuppliedValues(
() -> (String) configurationValues.get( AvailableSettings.JAKARTA_HBM2DDL_DB_NAME ),
() -> {
final Object value = configurationValues.get( AvailableSettings.DIALECT_DB_NAME );
if ( value != null ) {
DeprecationLogger.DEPRECATION_LOGGER.deprecatedSetting(
AvailableSettings.DIALECT_DB_NAME,
AvailableSettings.JAKARTA_HBM2DDL_DB_NAME
);
}
return (String) value;
}
);
Integer explicitDatabaseMajorVersion = NullnessHelper.coalesceSuppliedValues(
() -> ConfigurationHelper.getInteger( AvailableSettings.JAKARTA_HBM2DDL_DB_MAJOR_VERSION, configurationValues ),
() -> {
final Integer value = ConfigurationHelper.getInteger(
AvailableSettings.DIALECT_DB_MAJOR_VERSION,
configurationValues
);
if ( value != null ) {
DeprecationLogger.DEPRECATION_LOGGER.deprecatedSetting(
AvailableSettings.DIALECT_DB_MAJOR_VERSION,
AvailableSettings.JAKARTA_HBM2DDL_DB_MAJOR_VERSION
);
}
return value;
}
);
Integer explicitDatabaseMinorVersion = NullnessHelper.coalesceSuppliedValues(
() -> ConfigurationHelper.getInteger( AvailableSettings.JAKARTA_HBM2DDL_DB_MINOR_VERSION, configurationValues ),
() -> {
final Integer value = ConfigurationHelper.getInteger(
AvailableSettings.DIALECT_DB_MINOR_VERSION,
configurationValues
);
if ( value != null ) {
DeprecationLogger.DEPRECATION_LOGGER.deprecatedSetting(
AvailableSettings.DIALECT_DB_MINOR_VERSION,
AvailableSettings.JAKARTA_HBM2DDL_DB_MINOR_VERSION
);
}
return value;
}
);
Integer configuredDatabaseMajorVersion = explicitDatabaseMajorVersion;
Integer configuredDatabaseMinorVersion = explicitDatabaseMinorVersion;
String explicitDatabaseVersion = NullnessHelper.coalesceSuppliedValues(
() -> (String) configurationValues.get( AvailableSettings.JAKARTA_HBM2DDL_DB_VERSION ),
() -> {
final Object value = configurationValues.get( AvailableSettings.DIALECT_DB_VERSION );
if ( value != null ) {
DeprecationLogger.DEPRECATION_LOGGER.deprecatedSetting(
AvailableSettings.DIALECT_DB_VERSION,
AvailableSettings.JAKARTA_HBM2DDL_DB_VERSION
);
}
return (String) value;
}
,
() -> {
if ( configuredDatabaseMajorVersion != null ) {
return configuredDatabaseMinorVersion == null ? configuredDatabaseMajorVersion.toString() : (configuredDatabaseMajorVersion + "." + configuredDatabaseMinorVersion);
}
return null;
}
);
final String explicitDatabaseVersion =
getExplicitDatabaseVersion( configurationValues, explicitDatabaseMajorVersion, explicitDatabaseMinorVersion );
if ( explicitDatabaseMajorVersion == null && explicitDatabaseMinorVersion == null && explicitDatabaseVersion != null ) {
final String[] parts = explicitDatabaseVersion.split( "\\." );
@ -146,140 +78,279 @@ public class JdbcEnvironmentInitiator implements StandardServiceInitiator<JdbcEn
}
}
if ( useJdbcMetadata ) {
final JdbcConnectionAccess jdbcConnectionAccess = buildJdbcConnectionAccess( registry );
try {
final Connection connection = jdbcConnectionAccess.obtainConnection();
try {
final DatabaseMetaData dbmd = connection.getMetaData();
if ( log.isDebugEnabled() ) {
log.debugf(
"Database ->\n"
+ " name : %s\n"
+ " version : %s\n"
+ " major : %s\n"
+ " minor : %s",
dbmd.getDatabaseProductName(),
dbmd.getDatabaseProductVersion(),
dbmd.getDatabaseMajorVersion(),
dbmd.getDatabaseMinorVersion()
);
log.debugf(
"Driver ->\n"
+ " name : %s\n"
+ " version : %s\n"
+ " major : %s\n"
+ " minor : %s",
dbmd.getDriverName(),
dbmd.getDriverVersion(),
dbmd.getDriverMajorVersion(),
dbmd.getDriverMinorVersion()
);
log.debugf( "JDBC version : %s.%s", dbmd.getJDBCMajorVersion(), dbmd.getJDBCMinorVersion() );
}
final String databaseName;
final String databaseVersion;
final int databaseMajorVersion;
final int databaseMinorVersion;
if ( explicitDatabaseName == null ) {
databaseName = dbmd.getDatabaseProductName();
}
else {
databaseName = explicitDatabaseName;
}
if ( explicitDatabaseVersion == null ) {
databaseVersion = dbmd.getDatabaseProductVersion();
}
else {
databaseVersion = explicitDatabaseVersion;
}
if ( explicitDatabaseMajorVersion == null ) {
databaseMajorVersion = dbmd.getDatabaseMajorVersion();
}
else {
databaseMajorVersion = explicitDatabaseMajorVersion;
}
if ( explicitDatabaseMinorVersion == null ) {
databaseMinorVersion = dbmd.getDatabaseMinorVersion();
}
else {
databaseMinorVersion = explicitDatabaseMinorVersion;
}
final DialectResolutionInfo dialectResolutionInfo = new DialectResolutionInfoImpl(
dbmd,
databaseName,
databaseVersion,
databaseMajorVersion,
databaseMinorVersion,
dbmd.getDriverName(),
dbmd.getDriverMajorVersion(),
dbmd.getDriverMinorVersion(),
dbmd.getSQLKeywords()
);
return new JdbcEnvironmentImpl(
registry,
dialectFactory.buildDialect(
configurationValues,
() -> dialectResolutionInfo
),
dbmd,
jdbcConnectionAccess
);
}
catch (SQLException e) {
log.unableToObtainConnectionMetadata( e );
}
finally {
try {
jdbcConnectionAccess.releaseConnection( connection );
}
catch (SQLException ignore) {
}
}
}
catch (Exception e) {
log.unableToObtainConnectionToQueryMetadata( e );
}
if ( useJdbcMetadata( configurationValues ) ) {
return getJdbcEnvironmentUsingJdbcMetadata(
configurationValues,
registry,
dialectFactory,
explicitDatabaseName,
explicitDatabaseMajorVersion,
explicitDatabaseMinorVersion,
explicitDatabaseVersion);
}
else if ( explicitDialectConfiguration(
configurationValues,
explicitDatabaseName,
explicitDatabaseMajorVersion,
explicitDatabaseMinorVersion,
explicitDatabaseVersion) ) {
return getJdbcEnvironmentWithExplicitConfiguration(
configurationValues,
registry,
dialectFactory,
explicitDatabaseName,
explicitDatabaseMajorVersion,
explicitDatabaseMinorVersion,
explicitDatabaseVersion
);
}
else {
if (
(StringHelper.isNotEmpty( explicitDatabaseVersion ) || explicitDatabaseMajorVersion != null || explicitDatabaseMinorVersion != null)
&& ( StringHelper.isNotEmpty( explicitDatabaseName ) || isNotEmpty( configurationValues.get( AvailableSettings.DIALECT ) ) )
) {
return getJdbcEnvironmentWithDefaults( configurationValues, registry, dialectFactory );
}
}
private static JdbcEnvironmentImpl getJdbcEnvironmentWithDefaults(
Map<String, Object> configurationValues,
ServiceRegistryImplementor registry,
DialectFactory dialectFactory) {
return new JdbcEnvironmentImpl(
registry,
dialectFactory.buildDialect( configurationValues, null )
);
}
private static JdbcEnvironmentImpl getJdbcEnvironmentWithExplicitConfiguration(
Map<String, Object> configurationValues,
ServiceRegistryImplementor registry,
DialectFactory dialectFactory,
String explicitDatabaseName,
Integer explicitDatabaseMajorVersion,
Integer explicitDatabaseMinorVersion,
String explicitDatabaseVersion) {
final DialectResolutionInfo dialectResolutionInfo = new DialectResolutionInfoImpl(
null,
explicitDatabaseName,
explicitDatabaseVersion != null ? explicitDatabaseVersion : "0",
explicitDatabaseMajorVersion != null ? explicitDatabaseMajorVersion : 0,
explicitDatabaseMinorVersion != null ? explicitDatabaseMinorVersion : 0,
null,
0,
0,
null
);
return new JdbcEnvironmentImpl(
registry,
dialectFactory.buildDialect( configurationValues, () -> dialectResolutionInfo )
);
}
// 'hibernate.temp.use_jdbc_metadata_defaults' is a temporary magic value.
// The need for it is intended to be alleviated with future development, thus it is
// not defined as an Environment constant...
//
// it is used to control whether we should consult the JDBC metadata to determine
// certain default values; it is useful to *not* do this when the database
// may not be available (mainly in tools usage).
private static boolean useJdbcMetadata(Map<String, Object> configurationValues) {
return getBoolean(
"hibernate.temp.use_jdbc_metadata_defaults",
configurationValues,
true
);
}
private static String getExplicitDatabaseVersion(
Map<String, Object> configurationValues,
Integer configuredDatabaseMajorVersion,
Integer configuredDatabaseMinorVersion) {
return coalesceSuppliedValues(
() -> (String) configurationValues.get(AvailableSettings.JAKARTA_HBM2DDL_DB_VERSION),
() -> {
final Object value = configurationValues.get(AvailableSettings.DIALECT_DB_VERSION);
if ( value != null ) {
DEPRECATION_LOGGER.deprecatedSetting(
AvailableSettings.DIALECT_DB_VERSION,
AvailableSettings.JAKARTA_HBM2DDL_DB_VERSION
);
}
return (String) value;
}
,
() -> {
if ( configuredDatabaseMajorVersion != null ) {
return configuredDatabaseMinorVersion == null
? configuredDatabaseMajorVersion.toString()
: (configuredDatabaseMajorVersion + "." + configuredDatabaseMinorVersion);
}
return null;
}
);
}
private static Integer getExplicitDatabaseMinorVersion(Map<String, Object> configurationValues) {
return coalesceSuppliedValues(
() -> getInteger( JAKARTA_HBM2DDL_DB_MINOR_VERSION, configurationValues ),
() -> {
final Integer value = getInteger( DIALECT_DB_MINOR_VERSION, configurationValues );
if ( value != null ) {
DEPRECATION_LOGGER.deprecatedSetting( DIALECT_DB_MINOR_VERSION, JAKARTA_HBM2DDL_DB_MINOR_VERSION );
}
return value;
}
);
}
private static Integer getExplicitDatabaseMajorVersion(Map<String, Object> configurationValues) {
return coalesceSuppliedValues(
() -> getInteger( JAKARTA_HBM2DDL_DB_MAJOR_VERSION, configurationValues ),
() -> {
final Integer value = getInteger( DIALECT_DB_MAJOR_VERSION, configurationValues );
if ( value != null ) {
DEPRECATION_LOGGER.deprecatedSetting( DIALECT_DB_MAJOR_VERSION, JAKARTA_HBM2DDL_DB_MAJOR_VERSION );
}
return value;
}
);
}
private static String getExplicitDatabaseName(Map<String, Object> configurationValues) {
return coalesceSuppliedValues(
() -> (String) configurationValues.get(JAKARTA_HBM2DDL_DB_NAME),
() -> {
final Object value = configurationValues.get( DIALECT_DB_NAME );
if ( value != null ) {
DEPRECATION_LOGGER.deprecatedSetting( DIALECT_DB_NAME, JAKARTA_HBM2DDL_DB_NAME );
}
return (String) value;
}
);
}
private JdbcEnvironmentImpl getJdbcEnvironmentUsingJdbcMetadata(
Map<String, Object> configurationValues,
ServiceRegistryImplementor registry,
DialectFactory dialectFactory, String explicitDatabaseName,
Integer explicitDatabaseMajorVersion,
Integer explicitDatabaseMinorVersion,
String explicitDatabaseVersion) {
final JdbcConnectionAccess jdbcConnectionAccess = buildJdbcConnectionAccess(registry);
try {
final Connection connection = jdbcConnectionAccess.obtainConnection();
try {
final DatabaseMetaData dbmd = connection.getMetaData();
logDatabaseAndDriver( dbmd );
final String databaseName;
final String databaseVersion;
final int databaseMajorVersion;
final int databaseMinorVersion;
if ( explicitDatabaseName == null ) {
databaseName = dbmd.getDatabaseProductName();
}
else {
databaseName = explicitDatabaseName;
}
if ( explicitDatabaseVersion == null ) {
databaseVersion = dbmd.getDatabaseProductVersion();
}
else {
databaseVersion = explicitDatabaseVersion;
}
if ( explicitDatabaseMajorVersion == null ) {
databaseMajorVersion = dbmd.getDatabaseMajorVersion();
}
else {
databaseMajorVersion = explicitDatabaseMajorVersion;
}
if ( explicitDatabaseMinorVersion == null ) {
databaseMinorVersion = dbmd.getDatabaseMinorVersion();
}
else {
databaseMinorVersion = explicitDatabaseMinorVersion;
}
final DialectResolutionInfo dialectResolutionInfo = new DialectResolutionInfoImpl(
null,
explicitDatabaseName,
explicitDatabaseVersion != null ? explicitDatabaseVersion : "0",
explicitDatabaseMajorVersion != null ? explicitDatabaseMajorVersion : 0,
explicitDatabaseMinorVersion != null ? explicitDatabaseMinorVersion : 0,
null,
0,
0,
null
dbmd,
databaseName,
databaseVersion,
databaseMajorVersion,
databaseMinorVersion,
dbmd.getDriverName(),
dbmd.getDriverMajorVersion(),
dbmd.getDriverMinorVersion(),
dbmd.getSQLKeywords()
);
return new JdbcEnvironmentImpl(
registry,
dialectFactory.buildDialect(
configurationValues,
() -> dialectResolutionInfo
)
dialectFactory.buildDialect( configurationValues, () -> dialectResolutionInfo ),
dbmd,
jdbcConnectionAccess
);
}
catch ( SQLException e ) {
log.unableToObtainConnectionMetadata( e );
}
finally {
try {
jdbcConnectionAccess.releaseConnection( connection );
}
catch ( SQLException ignore ) {
}
}
}
catch ( Exception e ) {
log.unableToObtainConnectionToQueryMetadata( e );
}
// if we get here, either we were asked to not use JDBC metadata or accessing the JDBC metadata failed.
return new JdbcEnvironmentImpl( registry, dialectFactory.buildDialect( configurationValues, null ) );
// accessing the JDBC metadata failed
return getJdbcEnvironmentWithDefaults( configurationValues, registry, dialectFactory );
}
private static boolean isNotEmpty(Object o) {
private static void logDatabaseAndDriver(DatabaseMetaData dbmd) throws SQLException {
if ( log.isDebugEnabled() ) {
log.debugf(
"Database ->\n"
+ " name : %s\n"
+ " version : %s\n"
+ " major : %s\n"
+ " minor : %s",
dbmd.getDatabaseProductName(),
dbmd.getDatabaseProductVersion(),
dbmd.getDatabaseMajorVersion(),
dbmd.getDatabaseMinorVersion()
);
log.debugf(
"Driver ->\n"
+ " name : %s\n"
+ " version : %s\n"
+ " major : %s\n"
+ " minor : %s",
dbmd.getDriverName(),
dbmd.getDriverVersion(),
dbmd.getDriverMajorVersion(),
dbmd.getDriverMinorVersion()
);
log.debugf( "JDBC version : %s.%s", dbmd.getJDBCMajorVersion(), dbmd.getJDBCMinorVersion() );
}
}
private static boolean explicitDialectConfiguration(
Map<String, Object> configurationValues,
String explicitDatabaseName,
Integer explicitDatabaseMajorVersion,
Integer explicitDatabaseMinorVersion,
String explicitDatabaseVersion) {
return ( isNotEmpty(explicitDatabaseVersion) || explicitDatabaseMajorVersion != null || explicitDatabaseMinorVersion != null )
&& ( isNotEmpty(explicitDatabaseName) || isNotNullAndNotEmpty( configurationValues.get(AvailableSettings.DIALECT) ) );
}
private static boolean isNotNullAndNotEmpty(Object o) {
return o != null && ( !(o instanceof String) || !((String) o).isEmpty() );
}
private JdbcConnectionAccess buildJdbcConnectionAccess(ServiceRegistryImplementor registry) {
if ( !JdbcEnvironmentImpl.isMultiTenancyEnabled( registry ) ) {
if ( !isMultiTenancyEnabled( registry ) ) {
ConnectionProvider connectionProvider = registry.getService( ConnectionProvider.class );
return new ConnectionProviderJdbcConnectionAccess( connectionProvider );
}
@ -290,7 +361,7 @@ public class JdbcEnvironmentInitiator implements StandardServiceInitiator<JdbcEn
}
public static JdbcConnectionAccess buildBootstrapJdbcConnectionAccess(ServiceRegistryImplementor registry) {
if ( !JdbcEnvironmentImpl.isMultiTenancyEnabled( registry ) ) {
if ( !isMultiTenancyEnabled( registry ) ) {
ConnectionProvider connectionProvider = registry.getService( ConnectionProvider.class );
return new ConnectionProviderJdbcConnectionAccess( connectionProvider );
}

View File

@ -221,6 +221,12 @@ public interface DeprecationLogger extends BasicLogger {
// )
// void deprecatedComponentMapping(String name);
@LogMessage(level = WARN)
@Message(value = "%s does not need to be specified explicitly using 'hibernate.dialect' "
+ "(remove the property setting and it will be selected by default)",
id = 90000025)
void automaticDialect(String dialect);
@LogMessage(level = WARN)
@Message(value = "%s has been deprecated",
id = 90000026)