Browse Source

Use SQLExceptionSubclassTranslator by default (avoiding sql-error-codes.xml)

SQLErrorCodeSQLExceptionTranslator kicks in for user-provided sql-error-codes.xml files. It will still pick up Spring's legacy default error code mappings as well but only when triggered by a (potentially empty) user-provided file in the root of the classpath.

Closes gh-28216
pull/28631/head
Juergen Hoeller 4 years ago
parent
commit
083113d8a4
  1. 23
      spring-jdbc/src/main/java/org/springframework/jdbc/support/JdbcAccessor.java
  2. 22
      spring-jdbc/src/main/java/org/springframework/jdbc/support/JdbcTransactionManager.java
  3. 11
      spring-jdbc/src/main/java/org/springframework/jdbc/support/SQLErrorCodeSQLExceptionTranslator.java
  4. 14
      spring-jdbc/src/main/java/org/springframework/jdbc/support/SQLErrorCodesFactory.java
  5. 13
      spring-jdbc/src/test/java/org/springframework/jdbc/core/JdbcTemplateTests.java

23
spring-jdbc/src/main/java/org/springframework/jdbc/support/JdbcAccessor.java

@ -22,7 +22,6 @@ import org.apache.commons.logging.Log; @@ -22,7 +22,6 @@ import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.core.SpringProperties;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
@ -41,13 +40,6 @@ import org.springframework.util.Assert; @@ -41,13 +40,6 @@ import org.springframework.util.Assert;
*/
public abstract class JdbcAccessor implements InitializingBean {
/**
* Boolean flag controlled by a {@code spring.xml.ignore} system property that instructs Spring to
* ignore XML, i.e. to not initialize the XML-related infrastructure.
* <p>The default is "false".
*/
private static final boolean shouldIgnoreXml = SpringProperties.getFlag("spring.xml.ignore");
/** Logger available to subclasses. */
protected final Log logger = LogFactory.getLog(getClass());
@ -96,9 +88,12 @@ public abstract class JdbcAccessor implements InitializingBean { @@ -96,9 +88,12 @@ public abstract class JdbcAccessor implements InitializingBean {
* @see java.sql.DatabaseMetaData#getDatabaseProductName()
*/
public void setDatabaseProductName(String dbName) {
if (!shouldIgnoreXml) {
if (SQLErrorCodeSQLExceptionTranslator.hasUserProvidedErrorCodesFile()) {
this.exceptionTranslator = new SQLErrorCodeSQLExceptionTranslator(dbName);
}
else {
this.exceptionTranslator = new SQLExceptionSubclassTranslator();
}
}
/**
@ -128,15 +123,11 @@ public abstract class JdbcAccessor implements InitializingBean { @@ -128,15 +123,11 @@ public abstract class JdbcAccessor implements InitializingBean {
synchronized (this) {
exceptionTranslator = this.exceptionTranslator;
if (exceptionTranslator == null) {
DataSource dataSource = getDataSource();
if (shouldIgnoreXml) {
exceptionTranslator = new SQLExceptionSubclassTranslator();
}
else if (dataSource != null) {
exceptionTranslator = new SQLErrorCodeSQLExceptionTranslator(dataSource);
if (SQLErrorCodeSQLExceptionTranslator.hasUserProvidedErrorCodesFile()) {
exceptionTranslator = new SQLErrorCodeSQLExceptionTranslator(obtainDataSource());
}
else {
exceptionTranslator = new SQLStateSQLExceptionTranslator();
exceptionTranslator = new SQLExceptionSubclassTranslator();
}
this.exceptionTranslator = exceptionTranslator;
}

22
spring-jdbc/src/main/java/org/springframework/jdbc/support/JdbcTransactionManager.java

@ -1,5 +1,5 @@ @@ -1,5 +1,5 @@
/*
* Copyright 2002-2020 the original author or authors.
* Copyright 2002-2022 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.
@ -20,7 +20,6 @@ import java.sql.SQLException; @@ -20,7 +20,6 @@ import java.sql.SQLException;
import javax.sql.DataSource;
import org.springframework.core.SpringProperties;
import org.springframework.dao.DataAccessException;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.lang.Nullable;
@ -53,14 +52,6 @@ import org.springframework.lang.Nullable; @@ -53,14 +52,6 @@ import org.springframework.lang.Nullable;
@SuppressWarnings("serial")
public class JdbcTransactionManager extends DataSourceTransactionManager {
/**
* Boolean flag controlled by a {@code spring.xml.ignore} system property that instructs Spring to
* ignore XML, i.e. to not initialize the XML-related infrastructure.
* <p>The default is "false".
*/
private static final boolean shouldIgnoreXml = SpringProperties.getFlag("spring.xml.ignore");
@Nullable
private volatile SQLExceptionTranslator exceptionTranslator;
@ -97,9 +88,12 @@ public class JdbcTransactionManager extends DataSourceTransactionManager { @@ -97,9 +88,12 @@ public class JdbcTransactionManager extends DataSourceTransactionManager {
* @see java.sql.DatabaseMetaData#getDatabaseProductName()
*/
public void setDatabaseProductName(String dbName) {
if (!shouldIgnoreXml) {
if (SQLErrorCodeSQLExceptionTranslator.hasUserProvidedErrorCodesFile()) {
this.exceptionTranslator = new SQLErrorCodeSQLExceptionTranslator(dbName);
}
else {
this.exceptionTranslator = new SQLExceptionSubclassTranslator();
}
}
/**
@ -128,11 +122,11 @@ public class JdbcTransactionManager extends DataSourceTransactionManager { @@ -128,11 +122,11 @@ public class JdbcTransactionManager extends DataSourceTransactionManager {
synchronized (this) {
exceptionTranslator = this.exceptionTranslator;
if (exceptionTranslator == null) {
if (shouldIgnoreXml) {
exceptionTranslator = new SQLExceptionSubclassTranslator();
if (SQLErrorCodeSQLExceptionTranslator.hasUserProvidedErrorCodesFile()) {
exceptionTranslator = new SQLErrorCodeSQLExceptionTranslator(obtainDataSource());
}
else {
exceptionTranslator = new SQLErrorCodeSQLExceptionTranslator(obtainDataSource());
exceptionTranslator = new SQLExceptionSubclassTranslator();
}
this.exceptionTranslator = exceptionTranslator;
}

11
spring-jdbc/src/main/java/org/springframework/jdbc/support/SQLErrorCodeSQLExceptionTranslator.java

@ -23,6 +23,7 @@ import java.util.Arrays; @@ -23,6 +23,7 @@ import java.util.Arrays;
import javax.sql.DataSource;
import org.springframework.core.io.ClassPathResource;
import org.springframework.dao.CannotAcquireLockException;
import org.springframework.dao.CannotSerializeTransactionException;
import org.springframework.dao.DataAccessException;
@ -417,4 +418,14 @@ public class SQLErrorCodeSQLExceptionTranslator extends AbstractFallbackSQLExcep @@ -417,4 +418,14 @@ public class SQLErrorCodeSQLExceptionTranslator extends AbstractFallbackSQLExcep
}
}
/**
* Check whether there is a user-provided `sql-error-codes.xml` file
* in the root of the classpath.
*/
static boolean hasUserProvidedErrorCodesFile() {
return new ClassPathResource(SQLErrorCodesFactory.SQL_ERROR_CODE_OVERRIDE_PATH,
SQLErrorCodesFactory.class.getClassLoader()).exists();
}
}

14
spring-jdbc/src/main/java/org/springframework/jdbc/support/SQLErrorCodesFactory.java

@ -1,5 +1,5 @@ @@ -1,5 +1,5 @@
/*
* Copyright 2002-2020 the original author or authors.
* Copyright 2002-2022 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.
@ -28,6 +28,7 @@ import org.apache.commons.logging.LogFactory; @@ -28,6 +28,7 @@ import org.apache.commons.logging.LogFactory;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
import org.springframework.core.SpringProperties;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
import org.springframework.lang.Nullable;
@ -66,6 +67,13 @@ public class SQLErrorCodesFactory { @@ -66,6 +67,13 @@ public class SQLErrorCodesFactory {
private static final Log logger = LogFactory.getLog(SQLErrorCodesFactory.class);
/**
* Boolean flag controlled by a {@code spring.xml.ignore} system property that instructs Spring to
* ignore XML, i.e. to not initialize the XML-related infrastructure.
* <p>The default is "false".
*/
private static final boolean shouldIgnoreXml = SpringProperties.getFlag("spring.xml.ignore");
/**
* Keep track of a single instance so we can return it to classes that request it.
*/
@ -101,6 +109,10 @@ public class SQLErrorCodesFactory { @@ -101,6 +109,10 @@ public class SQLErrorCodesFactory {
* @see #loadResource(String)
*/
protected SQLErrorCodesFactory() {
if (shouldIgnoreXml) {
throw new UnsupportedOperationException("XML support disabled");
}
Map<String, SQLErrorCodes> errorCodes;
try {

13
spring-jdbc/src/test/java/org/springframework/jdbc/core/JdbcTemplateTests.java

@ -944,6 +944,8 @@ public class JdbcTemplateTests { @@ -944,6 +944,8 @@ public class JdbcTemplateTests {
mockDatabaseMetaData(false);
given(this.connection.createStatement()).willReturn(this.preparedStatement);
this.template.setExceptionTranslator(new SQLErrorCodeSQLExceptionTranslator(this.dataSource));
assertThatExceptionOfType(BadSqlGrammarException.class).isThrownBy(() ->
this.template.query(sql, (RowCallbackHandler) rs -> {
throw sqlException;
@ -955,20 +957,17 @@ public class JdbcTemplateTests { @@ -955,20 +957,17 @@ public class JdbcTemplateTests {
}
@Test
public void testSQLErrorCodeTranslationWithSpecifiedDbName() throws Exception {
public void testSQLErrorCodeTranslationWithSpecifiedDatabaseName() throws Exception {
final SQLException sqlException = new SQLException("I have a known problem", "99999", 1054);
final String sql = "SELECT ID FROM CUSTOMER";
given(this.resultSet.next()).willReturn(true);
given(this.connection.createStatement()).willReturn(this.preparedStatement);
JdbcTemplate template = new JdbcTemplate();
template.setDataSource(this.dataSource);
template.setDatabaseProductName("MySQL");
template.afterPropertiesSet();
this.template.setExceptionTranslator(new SQLErrorCodeSQLExceptionTranslator("MySQL"));
assertThatExceptionOfType(BadSqlGrammarException.class).isThrownBy(() ->
template.query(sql, (RowCallbackHandler) rs -> {
this.template.query(sql, (RowCallbackHandler) rs -> {
throw sqlException;
}))
.withCause(sqlException);
@ -983,7 +982,7 @@ public class JdbcTemplateTests { @@ -983,7 +982,7 @@ public class JdbcTemplateTests {
* to get the metadata
*/
@Test
public void testUseCustomSQLErrorCodeTranslator() throws Exception {
public void testUseCustomExceptionTranslator() throws Exception {
// Bad SQL state
final SQLException sqlException = new SQLException("I have a known problem", "07000", 1054);
final String sql = "SELECT ID FROM CUSTOMER";

Loading…
Cancel
Save