Skip to content

Commit 5199274

Browse files
committed
Add support for configurable custom translator
Closes gh-24634
1 parent 52c1927 commit 5199274

File tree

2 files changed

+59
-17
lines changed

2 files changed

+59
-17
lines changed

Diff for: spring-jdbc/src/main/java/org/springframework/jdbc/support/AbstractFallbackSQLExceptionTranslator.java

+42-5
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2020 the original author or authors.
2+
* Copyright 2002-2023 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -26,11 +26,15 @@
2626
import org.springframework.util.Assert;
2727

2828
/**
29-
* Base class for {@link SQLExceptionTranslator} implementations that allow for
30-
* fallback to some other {@link SQLExceptionTranslator}.
29+
* Base class for {@link SQLExceptionTranslator} implementations that allow for a
30+
* fallback to some other {@link SQLExceptionTranslator}, as well as for custom
31+
* overrides.
3132
*
3233
* @author Juergen Hoeller
3334
* @since 2.5.6
35+
* @see #doTranslate
36+
* @see #setFallbackTranslator
37+
* @see #setCustomTranslator
3438
*/
3539
public abstract class AbstractFallbackSQLExceptionTranslator implements SQLExceptionTranslator {
3640

@@ -40,23 +44,47 @@ public abstract class AbstractFallbackSQLExceptionTranslator implements SQLExcep
4044
@Nullable
4145
private SQLExceptionTranslator fallbackTranslator;
4246

47+
@Nullable
48+
private SQLExceptionTranslator customTranslator;
49+
4350

4451
/**
45-
* Override the default SQL state fallback translator
46-
* (typically a {@link SQLStateSQLExceptionTranslator}).
52+
* Set the fallback translator to use when this translator cannot find a
53+
* specific match itself.
4754
*/
4855
public void setFallbackTranslator(@Nullable SQLExceptionTranslator fallback) {
4956
this.fallbackTranslator = fallback;
5057
}
5158

5259
/**
5360
* Return the fallback exception translator, if any.
61+
* @see #setFallbackTranslator
5462
*/
5563
@Nullable
5664
public SQLExceptionTranslator getFallbackTranslator() {
5765
return this.fallbackTranslator;
5866
}
5967

68+
/**
69+
* Set a custom exception translator to override any match that this translator
70+
* would find. Note that such a custom {@link SQLExceptionTranslator} delegate
71+
* is meant to return {@code null} if it does not have an override itself.
72+
* @since 6.1
73+
*/
74+
public void setCustomTranslator(@Nullable SQLExceptionTranslator customTranslator) {
75+
this.customTranslator = customTranslator;
76+
}
77+
78+
/**
79+
* Return a custom exception translator, if any.
80+
* @since 6.1
81+
* @see #setCustomTranslator
82+
*/
83+
@Nullable
84+
public SQLExceptionTranslator getCustomTranslator() {
85+
return this.customTranslator;
86+
}
87+
6088

6189
/**
6290
* Pre-checks the arguments, calls {@link #doTranslate}, and invokes the
@@ -67,6 +95,15 @@ public SQLExceptionTranslator getFallbackTranslator() {
6795
public DataAccessException translate(String task, @Nullable String sql, SQLException ex) {
6896
Assert.notNull(ex, "Cannot translate a null SQLException");
6997

98+
SQLExceptionTranslator custom = getCustomTranslator();
99+
if (custom != null) {
100+
DataAccessException dae = custom.translate(task, sql, ex);
101+
if (dae != null) {
102+
// Custom exception match found.
103+
return dae;
104+
}
105+
}
106+
70107
DataAccessException dae = doTranslate(task, sql, ex);
71108
if (dae != null) {
72109
// Specific exception match found.

Diff for: spring-jdbc/src/main/java/org/springframework/jdbc/support/SQLErrorCodeSQLExceptionTranslator.java

+17-12
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,11 @@
6060
* of the class path (e.g. in the "/WEB-INF/classes" directory), as long as the
6161
* Spring JDBC package is loaded from the same ClassLoader.
6262
*
63+
* <p>This translator is commonly used by default if a user-provided `sql-error-codes.xml`
64+
* file has been found in the root of the classpath, as a signal to use this strategy.
65+
* Otherwise, {@link SQLExceptionSubclassTranslator} serves as the default translator
66+
* as of 6.0.
67+
*
6368
* @author Rod Johnson
6469
* @author Thomas Risberg
6570
* @author Juergen Hoeller
@@ -75,11 +80,10 @@ public class SQLErrorCodeSQLExceptionTranslator extends AbstractFallbackSQLExcep
7580
private static final int MESSAGE_SQL_THROWABLE_CONSTRUCTOR = 4;
7681
private static final int MESSAGE_SQL_SQLEX_CONSTRUCTOR = 5;
7782

78-
private static final boolean USER_PROVIDED_ERROR_CODES_FILE_PRESENT =
79-
new ClassPathResource(SQLErrorCodesFactory.SQL_ERROR_CODE_OVERRIDE_PATH, SQLErrorCodesFactory.class.getClassLoader()).exists();
80-
83+
private static final boolean userProvidedErrorCodesFilePresent =
84+
new ClassPathResource(SQLErrorCodesFactory.SQL_ERROR_CODE_OVERRIDE_PATH,
85+
SQLErrorCodesFactory.class.getClassLoader()).exists();
8186

82-
/** Error codes used by this translator. */
8387
@Nullable
8488
private SingletonSupplier<SQLErrorCodes> sqlErrorCodes;
8589

@@ -198,9 +202,9 @@ protected DataAccessException doTranslate(String task, @Nullable String sql, SQL
198202
if (sqlErrorCodes != null) {
199203
SQLExceptionTranslator customTranslator = sqlErrorCodes.getCustomSqlExceptionTranslator();
200204
if (customTranslator != null) {
201-
DataAccessException customDex = customTranslator.translate(task, sql, sqlEx);
202-
if (customDex != null) {
203-
return customDex;
205+
dae = customTranslator.translate(task, sql, sqlEx);
206+
if (dae != null) {
207+
return dae;
204208
}
205209
}
206210
}
@@ -228,11 +232,10 @@ protected DataAccessException doTranslate(String task, @Nullable String sql, SQL
228232
for (CustomSQLErrorCodesTranslation customTranslation : customTranslations) {
229233
if (Arrays.binarySearch(customTranslation.getErrorCodes(), errorCode) >= 0 &&
230234
customTranslation.getExceptionClass() != null) {
231-
DataAccessException customException = createCustomException(
232-
task, sql, sqlEx, customTranslation.getExceptionClass());
233-
if (customException != null) {
235+
dae = createCustomException(task, sql, sqlEx, customTranslation.getExceptionClass());
236+
if (dae != null) {
234237
logTranslation(task, sql, sqlEx, true);
235-
return customException;
238+
return dae;
236239
}
237240
}
238241
}
@@ -306,7 +309,9 @@ else if (Arrays.binarySearch(sqlErrorCodes.getCannotSerializeTransactionCodes(),
306309
* resulting from custom translation. This exception should include the {@code sqlEx} parameter
307310
* as a nested root cause. This implementation always returns {@code null}, meaning that the
308311
* translator always falls back to the default error codes.
312+
* @deprecated as of 6.1, in favor of {@link #setCustomTranslator}
309313
*/
314+
@Deprecated(since = "6.1")
310315
@Nullable
311316
protected DataAccessException customTranslate(String task, @Nullable String sql, SQLException sqlEx) {
312317
return null;
@@ -426,7 +431,7 @@ private void logTranslation(String task, @Nullable String sql, SQLException sqlE
426431
* in the root of the classpath.
427432
*/
428433
static boolean hasUserProvidedErrorCodesFile() {
429-
return USER_PROVIDED_ERROR_CODES_FILE_PRESENT;
434+
return userProvidedErrorCodesFilePresent;
430435
}
431436

432437
}

0 commit comments

Comments
 (0)