Protect against null return value from DataSource.getConnection()

Issue: SPR-15641
master
Juergen Hoeller 7 years ago
parent bf66f45283
commit ee5fa2633a
  1. 10
      spring-jdbc/src/main/java/org/springframework/jdbc/CannotGetJdbcConnectionException.java
  2. 27
      spring-jdbc/src/main/java/org/springframework/jdbc/datasource/DataSourceUtils.java
  3. 6
      spring-jdbc/src/main/java/org/springframework/jdbc/datasource/embedded/AbstractEmbeddedDatabaseConfigurer.java
  4. 6
      spring-jdbc/src/main/java/org/springframework/jdbc/support/DatabaseStartupValidator.java

@ -25,10 +25,20 @@ import org.springframework.lang.Nullable;
* Fatal exception thrown when we can't connect to an RDBMS using JDBC.
*
* @author Rod Johnson
* @author Juergen Hoeller
*/
@SuppressWarnings("serial")
public class CannotGetJdbcConnectionException extends DataAccessResourceFailureException {
/**
* Constructor for CannotGetJdbcConnectionException.
* @param msg the detail message
* @since 5.0
*/
public CannotGetJdbcConnectionException(String msg) {
super(msg);
}
/**
* Constructor for CannotGetJdbcConnectionException.
* @param msg the detail message

@ -78,7 +78,10 @@ public abstract class DataSourceUtils {
return doGetConnection(dataSource);
}
catch (SQLException ex) {
throw new CannotGetJdbcConnectionException("Could not get JDBC Connection", ex);
throw new CannotGetJdbcConnectionException("Failed to obtain JDBC Connection", ex);
}
catch (IllegalStateException ex) {
throw new CannotGetJdbcConnectionException("Failed to obtain JDBC Connection: " + ex.getMessage());
}
}
@ -102,14 +105,14 @@ public abstract class DataSourceUtils {
conHolder.requested();
if (!conHolder.hasConnection()) {
logger.debug("Fetching resumed JDBC Connection from DataSource");
conHolder.setConnection(dataSource.getConnection());
conHolder.setConnection(fetchConnection(dataSource));
}
return conHolder.getConnection();
}
// Else we either got no holder or an empty thread-bound holder here.
logger.debug("Fetching JDBC Connection from DataSource");
Connection con = dataSource.getConnection();
Connection con = fetchConnection(dataSource);
if (TransactionSynchronizationManager.isSynchronizationActive()) {
logger.debug("Registering transaction synchronization for JDBC Connection");
@ -134,6 +137,24 @@ public abstract class DataSourceUtils {
return con;
}
/**
* Actually fetch a {@link Connection} from the given {@link DataSource},
* defensively turning an unexpected {@code null} return value from
* {@link DataSource#getConnection()} into an {@link IllegalStateException}.
* @param dataSource the DataSource to obtain Connections from
* @return a JDBC Connection from the given DataSource (never {@code null})
* @throws SQLException if thrown by JDBC methods
* @throws IllegalStateException if the DataSource returned a null value
* @see DataSource#getConnection()
*/
private static Connection fetchConnection(DataSource dataSource) throws SQLException {
Connection con = dataSource.getConnection();
if (con == null) {
throw new IllegalStateException("DataSource returned null from getConnection(): " + dataSource);
}
return con;
}
/**
* Prepare the given Connection with the given transaction semantics.
* @param con the Connection to prepare

@ -1,5 +1,5 @@
/*
* Copyright 2002-2015 the original author or authors.
* Copyright 2002-2017 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -40,7 +40,9 @@ abstract class AbstractEmbeddedDatabaseConfigurer implements EmbeddedDatabaseCon
Connection con = null;
try {
con = dataSource.getConnection();
con.createStatement().execute("SHUTDOWN");
if (con != null) {
con.createStatement().execute("SHUTDOWN");
}
}
catch (SQLException ex) {
logger.warn("Could not shut down embedded database", ex);

@ -1,5 +1,5 @@
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2017 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -112,6 +112,10 @@ public class DatabaseStartupValidator implements InitializingBean {
Statement stmt = null;
try {
con = this.dataSource.getConnection();
if (con == null) {
throw new CannotGetJdbcConnectionException("Failed to execute validation query: " +
"DataSource returned null from getConnection(): " + this.dataSource);
}
stmt = con.createStatement();
stmt.execute(this.validationQuery);
validated = true;

Loading…
Cancel
Save