Skip to content

Commit efe943d

Browse files
committed
WebSphereUowTransactionManager logs overridden application exceptions
Issue: SPR-16102
1 parent bf60253 commit efe943d

File tree

3 files changed

+51
-42
lines changed

3 files changed

+51
-42
lines changed

spring-tx/src/main/java/org/springframework/transaction/interceptor/TransactionAspectSupport.java

+26-28
Original file line numberDiff line numberDiff line change
@@ -306,6 +306,8 @@ protected Object invokeWithinTransaction(Method method, @Nullable Class<?> targe
306306
}
307307

308308
else {
309+
final ThrowableHolder throwableHolder = new ThrowableHolder();
310+
309311
// It's a CallbackPreferringPlatformTransactionManager: pass a TransactionCallback in.
310312
try {
311313
Object result = ((CallbackPreferringPlatformTransactionManager) tm).execute(txAttr, status -> {
@@ -325,25 +327,37 @@ protected Object invokeWithinTransaction(Method method, @Nullable Class<?> targe
325327
}
326328
else {
327329
// A normal return value: will lead to a commit.
328-
return new ThrowableHolder(ex);
330+
throwableHolder.throwable = ex;
331+
return null;
329332
}
330333
}
331334
finally {
332335
cleanupTransactionInfo(txInfo);
333336
}
334337
});
335338

336-
// Check result: It might indicate a Throwable to rethrow.
337-
if (result instanceof ThrowableHolder) {
338-
throw ((ThrowableHolder) result).getThrowable();
339-
}
340-
else {
341-
return result;
339+
// Check result state: It might indicate a Throwable to rethrow.
340+
if (throwableHolder.throwable != null) {
341+
throw throwableHolder.throwable;
342342
}
343+
return result;
343344
}
344345
catch (ThrowableHolderException ex) {
345346
throw ex.getCause();
346347
}
348+
catch (TransactionSystemException ex2) {
349+
if (throwableHolder.throwable != null) {
350+
logger.error("Application exception overridden by commit exception", throwableHolder.throwable);
351+
ex2.initApplicationException(throwableHolder.throwable);
352+
}
353+
throw ex2;
354+
}
355+
catch (Throwable ex2) {
356+
if (throwableHolder.throwable != null) {
357+
logger.error("Application exception overridden by commit exception", throwableHolder.throwable);
358+
}
359+
throw ex2;
360+
}
347361
}
348362
}
349363

@@ -540,14 +554,10 @@ protected void completeTransactionAfterThrowing(@Nullable TransactionInfo txInfo
540554
ex2.initApplicationException(ex);
541555
throw ex2;
542556
}
543-
catch (RuntimeException ex2) {
557+
catch (RuntimeException | Error ex2) {
544558
logger.error("Application exception overridden by rollback exception", ex);
545559
throw ex2;
546560
}
547-
catch (Error err) {
548-
logger.error("Application exception overridden by rollback error", ex);
549-
throw err;
550-
}
551561
}
552562
else {
553563
// We don't roll back on this exception.
@@ -560,14 +570,10 @@ protected void completeTransactionAfterThrowing(@Nullable TransactionInfo txInfo
560570
ex2.initApplicationException(ex);
561571
throw ex2;
562572
}
563-
catch (RuntimeException ex2) {
573+
catch (RuntimeException | Error ex2) {
564574
logger.error("Application exception overridden by commit exception", ex);
565575
throw ex2;
566576
}
567-
catch (Error err) {
568-
logger.error("Application exception overridden by commit error", ex);
569-
throw err;
570-
}
571577
}
572578
}
573579
}
@@ -679,20 +685,12 @@ protected interface InvocationCallback {
679685

680686

681687
/**
682-
* Internal holder class for a Throwable, used as a return value
683-
* from a TransactionCallback (to be subsequently unwrapped again).
688+
* Internal holder class for a Throwable in a callback transaction model.
684689
*/
685690
private static class ThrowableHolder {
686691

687-
private final Throwable throwable;
688-
689-
public ThrowableHolder(Throwable throwable) {
690-
this.throwable = throwable;
691-
}
692-
693-
public final Throwable getThrowable() {
694-
return this.throwable;
695-
}
692+
@Nullable
693+
public Throwable throwable;
696694
}
697695

698696

spring-tx/src/main/java/org/springframework/transaction/jta/WebSphereUowTransactionManager.java

+24-9
Original file line numberDiff line numberDiff line change
@@ -261,7 +261,8 @@ public <T> T execute(@Nullable TransactionDefinition definition, TransactionCall
261261
"Transaction propagation 'nested' not supported for WebSphere UOW transactions");
262262
}
263263
if (pb == TransactionDefinition.PROPAGATION_SUPPORTS ||
264-
pb == TransactionDefinition.PROPAGATION_REQUIRED || pb == TransactionDefinition.PROPAGATION_MANDATORY) {
264+
pb == TransactionDefinition.PROPAGATION_REQUIRED ||
265+
pb == TransactionDefinition.PROPAGATION_MANDATORY) {
265266
joinTx = true;
266267
newSynch = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER);
267268
}
@@ -279,7 +280,8 @@ else if (pb == TransactionDefinition.PROPAGATION_NOT_SUPPORTED) {
279280
"Transaction propagation 'mandatory' but no existing transaction found");
280281
}
281282
if (pb == TransactionDefinition.PROPAGATION_SUPPORTS ||
282-
pb == TransactionDefinition.PROPAGATION_NOT_SUPPORTED || pb == TransactionDefinition.PROPAGATION_NEVER) {
283+
pb == TransactionDefinition.PROPAGATION_NOT_SUPPORTED ||
284+
pb == TransactionDefinition.PROPAGATION_NEVER) {
283285
uowType = UOWSynchronizationRegistry.UOW_TYPE_LOCAL_TRANSACTION;
284286
newSynch = (getTransactionSynchronization() == SYNCHRONIZATION_ALWAYS);
285287
}
@@ -293,26 +295,31 @@ else if (pb == TransactionDefinition.PROPAGATION_NOT_SUPPORTED) {
293295
logger.debug("Creating new transaction with name [" + definition.getName() + "]: " + definition);
294296
}
295297
SuspendedResourcesHolder suspendedResources = (!joinTx ? suspend(null) : null);
298+
UOWActionAdapter<T> action = null;
296299
try {
297300
if (definition.getTimeout() > TransactionDefinition.TIMEOUT_DEFAULT) {
298301
uowManager.setUOWTimeout(uowType, definition.getTimeout());
299302
}
300303
if (debug) {
301304
logger.debug("Invoking WebSphere UOW action: type=" + uowType + ", join=" + joinTx);
302305
}
303-
UOWActionAdapter<T> action = new UOWActionAdapter<>(
306+
action = new UOWActionAdapter<>(
304307
definition, callback, (uowType == UOWManager.UOW_TYPE_GLOBAL_TRANSACTION), !joinTx, newSynch, debug);
305308
uowManager.runUnderUOW(uowType, joinTx, action);
306309
if (debug) {
307310
logger.debug("Returned from WebSphere UOW action: type=" + uowType + ", join=" + joinTx);
308311
}
309312
return action.getResult();
310313
}
311-
catch (UOWException ex) {
312-
throw new TransactionSystemException("UOWManager transaction processing failed", ex);
313-
}
314-
catch (UOWActionException ex) {
315-
throw new TransactionSystemException("UOWManager threw unexpected UOWActionException", ex);
314+
catch (UOWException | UOWActionException ex) {
315+
TransactionSystemException tse =
316+
new TransactionSystemException("UOWManager transaction processing failed", ex);
317+
Throwable appEx = action.getException();
318+
if (appEx != null) {
319+
logger.error("Application exception overridden by rollback exception", appEx);
320+
tse.initApplicationException(appEx);
321+
}
322+
throw tse;
316323
}
317324
finally {
318325
if (suspendedResources != null) {
@@ -368,12 +375,15 @@ public void run() {
368375
}
369376
catch (Throwable ex) {
370377
this.exception = ex;
378+
if (status.isDebug()) {
379+
logger.debug("Rolling back on application exception from transaction callback", ex);
380+
}
371381
uowManager.setRollbackOnly();
372382
}
373383
finally {
374384
if (status.isLocalRollbackOnly()) {
375385
if (status.isDebug()) {
376-
logger.debug("Transactional code has requested rollback");
386+
logger.debug("Transaction callback has explicitly requested rollback");
377387
}
378388
uowManager.setRollbackOnly();
379389
}
@@ -396,6 +406,11 @@ public T getResult() {
396406
return this.result;
397407
}
398408

409+
@Nullable
410+
public Throwable getException() {
411+
return this.exception;
412+
}
413+
399414
@Override
400415
public boolean isRollbackOnly() {
401416
return obtainUOWManager().getRollbackOnly();

spring-tx/src/main/java/org/springframework/transaction/support/TransactionTemplate.java

+1-5
Original file line numberDiff line numberDiff line change
@@ -172,14 +172,10 @@ private void rollbackOnException(TransactionStatus status, Throwable ex) throws
172172
ex2.initApplicationException(ex);
173173
throw ex2;
174174
}
175-
catch (RuntimeException ex2) {
175+
catch (RuntimeException | Error ex2) {
176176
logger.error("Application exception overridden by rollback exception", ex);
177177
throw ex2;
178178
}
179-
catch (Error err) {
180-
logger.error("Application exception overridden by rollback error", ex);
181-
throw err;
182-
}
183179
}
184180

185181
}

0 commit comments

Comments
 (0)