11/*
2- * Copyright 2002-2018 the original author or authors.
2+ * Copyright 2002-2020 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.
3535import org .springframework .jdbc .BadSqlGrammarException ;
3636import org .springframework .jdbc .InvalidResultSetAccessException ;
3737import org .springframework .lang .Nullable ;
38+ import org .springframework .util .function .SingletonSupplier ;
39+ import org .springframework .util .function .SupplierUtils ;
3840
3941/**
4042 * Implementation of {@link SQLExceptionTranslator} that analyzes vendor-specific error codes.
@@ -76,7 +78,7 @@ public class SQLErrorCodeSQLExceptionTranslator extends AbstractFallbackSQLExcep
7678
7779 /** Error codes used by this translator. */
7880 @ Nullable
79- private SQLErrorCodes sqlErrorCodes ;
81+ private SingletonSupplier < SQLErrorCodes > sqlErrorCodes ;
8082
8183
8284 /**
@@ -120,7 +122,7 @@ public SQLErrorCodeSQLExceptionTranslator(String dbName) {
120122 */
121123 public SQLErrorCodeSQLExceptionTranslator (SQLErrorCodes sec ) {
122124 this ();
123- this .sqlErrorCodes = sec ;
125+ this .sqlErrorCodes = SingletonSupplier . of ( sec ) ;
124126 }
125127
126128
@@ -134,7 +136,9 @@ public SQLErrorCodeSQLExceptionTranslator(SQLErrorCodes sec) {
134136 * @see java.sql.DatabaseMetaData#getDatabaseProductName()
135137 */
136138 public void setDataSource (DataSource dataSource ) {
137- this .sqlErrorCodes = SQLErrorCodesFactory .getInstance ().getErrorCodes (dataSource );
139+ this .sqlErrorCodes =
140+ SingletonSupplier .of (() -> SQLErrorCodesFactory .getInstance ().resolveErrorCodes (dataSource ));
141+ this .sqlErrorCodes .get (); // try early initialization - otherwise the supplier will retry later
138142 }
139143
140144 /**
@@ -146,15 +150,15 @@ public void setDataSource(DataSource dataSource) {
146150 * @see java.sql.DatabaseMetaData#getDatabaseProductName()
147151 */
148152 public void setDatabaseProductName (String dbName ) {
149- this .sqlErrorCodes = SQLErrorCodesFactory .getInstance ().getErrorCodes (dbName );
153+ this .sqlErrorCodes = SingletonSupplier . of ( SQLErrorCodesFactory .getInstance ().getErrorCodes (dbName ) );
150154 }
151155
152156 /**
153157 * Set custom error codes to be used for translation.
154158 * @param sec custom error codes to use
155159 */
156160 public void setSqlErrorCodes (@ Nullable SQLErrorCodes sec ) {
157- this .sqlErrorCodes = sec ;
161+ this .sqlErrorCodes = SingletonSupplier . ofNullable ( sec ) ;
158162 }
159163
160164 /**
@@ -164,7 +168,7 @@ public void setSqlErrorCodes(@Nullable SQLErrorCodes sec) {
164168 */
165169 @ Nullable
166170 public SQLErrorCodes getSqlErrorCodes () {
167- return this .sqlErrorCodes ;
171+ return SupplierUtils . resolve ( this .sqlErrorCodes ) ;
168172 }
169173
170174
@@ -175,7 +179,6 @@ protected DataAccessException doTranslate(String task, @Nullable String sql, SQL
175179 if (sqlEx instanceof BatchUpdateException && sqlEx .getNextException () != null ) {
176180 SQLException nestedSqlEx = sqlEx .getNextException ();
177181 if (nestedSqlEx .getErrorCode () > 0 || nestedSqlEx .getSQLState () != null ) {
178- logger .debug ("Using nested SQLException from the BatchUpdateException" );
179182 sqlEx = nestedSqlEx ;
180183 }
181184 }
@@ -187,8 +190,9 @@ protected DataAccessException doTranslate(String task, @Nullable String sql, SQL
187190 }
188191
189192 // Next, try the custom SQLException translator, if available.
190- if (this .sqlErrorCodes != null ) {
191- SQLExceptionTranslator customTranslator = this .sqlErrorCodes .getCustomSqlExceptionTranslator ();
193+ SQLErrorCodes sqlErrorCodes = getSqlErrorCodes ();
194+ if (sqlErrorCodes != null ) {
195+ SQLExceptionTranslator customTranslator = sqlErrorCodes .getCustomSqlExceptionTranslator ();
192196 if (customTranslator != null ) {
193197 DataAccessException customDex = customTranslator .translate (task , sql , sqlEx );
194198 if (customDex != null ) {
@@ -198,9 +202,9 @@ protected DataAccessException doTranslate(String task, @Nullable String sql, SQL
198202 }
199203
200204 // Check SQLErrorCodes with corresponding error code, if available.
201- if (this . sqlErrorCodes != null ) {
205+ if (sqlErrorCodes != null ) {
202206 String errorCode ;
203- if (this . sqlErrorCodes .isUseSqlStateForTranslation ()) {
207+ if (sqlErrorCodes .isUseSqlStateForTranslation ()) {
204208 errorCode = sqlEx .getSQLState ();
205209 }
206210 else {
@@ -215,7 +219,7 @@ protected DataAccessException doTranslate(String task, @Nullable String sql, SQL
215219
216220 if (errorCode != null ) {
217221 // Look for defined custom translations first.
218- CustomSQLErrorCodesTranslation [] customTranslations = this . sqlErrorCodes .getCustomTranslations ();
222+ CustomSQLErrorCodesTranslation [] customTranslations = sqlErrorCodes .getCustomTranslations ();
219223 if (customTranslations != null ) {
220224 for (CustomSQLErrorCodesTranslation customTranslation : customTranslations ) {
221225 if (Arrays .binarySearch (customTranslation .getErrorCodes (), errorCode ) >= 0 &&
@@ -230,43 +234,43 @@ protected DataAccessException doTranslate(String task, @Nullable String sql, SQL
230234 }
231235 }
232236 // Next, look for grouped error codes.
233- if (Arrays .binarySearch (this . sqlErrorCodes .getBadSqlGrammarCodes (), errorCode ) >= 0 ) {
237+ if (Arrays .binarySearch (sqlErrorCodes .getBadSqlGrammarCodes (), errorCode ) >= 0 ) {
234238 logTranslation (task , sql , sqlEx , false );
235239 return new BadSqlGrammarException (task , (sql != null ? sql : "" ), sqlEx );
236240 }
237- else if (Arrays .binarySearch (this . sqlErrorCodes .getInvalidResultSetAccessCodes (), errorCode ) >= 0 ) {
241+ else if (Arrays .binarySearch (sqlErrorCodes .getInvalidResultSetAccessCodes (), errorCode ) >= 0 ) {
238242 logTranslation (task , sql , sqlEx , false );
239243 return new InvalidResultSetAccessException (task , (sql != null ? sql : "" ), sqlEx );
240244 }
241- else if (Arrays .binarySearch (this . sqlErrorCodes .getDuplicateKeyCodes (), errorCode ) >= 0 ) {
245+ else if (Arrays .binarySearch (sqlErrorCodes .getDuplicateKeyCodes (), errorCode ) >= 0 ) {
242246 logTranslation (task , sql , sqlEx , false );
243247 return new DuplicateKeyException (buildMessage (task , sql , sqlEx ), sqlEx );
244248 }
245- else if (Arrays .binarySearch (this . sqlErrorCodes .getDataIntegrityViolationCodes (), errorCode ) >= 0 ) {
249+ else if (Arrays .binarySearch (sqlErrorCodes .getDataIntegrityViolationCodes (), errorCode ) >= 0 ) {
246250 logTranslation (task , sql , sqlEx , false );
247251 return new DataIntegrityViolationException (buildMessage (task , sql , sqlEx ), sqlEx );
248252 }
249- else if (Arrays .binarySearch (this . sqlErrorCodes .getPermissionDeniedCodes (), errorCode ) >= 0 ) {
253+ else if (Arrays .binarySearch (sqlErrorCodes .getPermissionDeniedCodes (), errorCode ) >= 0 ) {
250254 logTranslation (task , sql , sqlEx , false );
251255 return new PermissionDeniedDataAccessException (buildMessage (task , sql , sqlEx ), sqlEx );
252256 }
253- else if (Arrays .binarySearch (this . sqlErrorCodes .getDataAccessResourceFailureCodes (), errorCode ) >= 0 ) {
257+ else if (Arrays .binarySearch (sqlErrorCodes .getDataAccessResourceFailureCodes (), errorCode ) >= 0 ) {
254258 logTranslation (task , sql , sqlEx , false );
255259 return new DataAccessResourceFailureException (buildMessage (task , sql , sqlEx ), sqlEx );
256260 }
257- else if (Arrays .binarySearch (this . sqlErrorCodes .getTransientDataAccessResourceCodes (), errorCode ) >= 0 ) {
261+ else if (Arrays .binarySearch (sqlErrorCodes .getTransientDataAccessResourceCodes (), errorCode ) >= 0 ) {
258262 logTranslation (task , sql , sqlEx , false );
259263 return new TransientDataAccessResourceException (buildMessage (task , sql , sqlEx ), sqlEx );
260264 }
261- else if (Arrays .binarySearch (this . sqlErrorCodes .getCannotAcquireLockCodes (), errorCode ) >= 0 ) {
265+ else if (Arrays .binarySearch (sqlErrorCodes .getCannotAcquireLockCodes (), errorCode ) >= 0 ) {
262266 logTranslation (task , sql , sqlEx , false );
263267 return new CannotAcquireLockException (buildMessage (task , sql , sqlEx ), sqlEx );
264268 }
265- else if (Arrays .binarySearch (this . sqlErrorCodes .getDeadlockLoserCodes (), errorCode ) >= 0 ) {
269+ else if (Arrays .binarySearch (sqlErrorCodes .getDeadlockLoserCodes (), errorCode ) >= 0 ) {
266270 logTranslation (task , sql , sqlEx , false );
267271 return new DeadlockLoserDataAccessException (buildMessage (task , sql , sqlEx ), sqlEx );
268272 }
269- else if (Arrays .binarySearch (this . sqlErrorCodes .getCannotSerializeTransactionCodes (), errorCode ) >= 0 ) {
273+ else if (Arrays .binarySearch (sqlErrorCodes .getCannotSerializeTransactionCodes (), errorCode ) >= 0 ) {
270274 logTranslation (task , sql , sqlEx , false );
271275 return new CannotSerializeTransactionException (buildMessage (task , sql , sqlEx ), sqlEx );
272276 }
@@ -276,7 +280,7 @@ else if (Arrays.binarySearch(this.sqlErrorCodes.getCannotSerializeTransactionCod
276280 // We couldn't identify it more precisely - let's hand it over to the SQLState fallback translator.
277281 if (logger .isDebugEnabled ()) {
278282 String codes ;
279- if (this . sqlErrorCodes != null && this . sqlErrorCodes .isUseSqlStateForTranslation ()) {
283+ if (sqlErrorCodes != null && sqlErrorCodes .isUseSqlStateForTranslation ()) {
280284 codes = "SQL state '" + sqlEx .getSQLState () + "', error code '" + sqlEx .getErrorCode ();
281285 }
282286 else {
0 commit comments