Skip to content

Commit 75a813a

Browse files
committed
WebSphereUowTransactionManager logs overridden application exceptions
Issue: SPR-16102 (cherry picked from commit efe943d)
1 parent 6446ffd commit 75a813a

File tree

2 files changed

+55
-25
lines changed

2 files changed

+55
-25
lines changed

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

Lines changed: 23 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -294,6 +294,8 @@ protected Object invokeWithinTransaction(Method method, Class<?> targetClass, fi
294294
}
295295

296296
else {
297+
final ThrowableHolder throwableHolder = new ThrowableHolder();
298+
297299
// It's a CallbackPreferringPlatformTransactionManager: pass a TransactionCallback in.
298300
try {
299301
Object result = ((CallbackPreferringPlatformTransactionManager) tm).execute(txAttr,
@@ -316,7 +318,8 @@ public Object doInTransaction(TransactionStatus status) {
316318
}
317319
else {
318320
// A normal return value: will lead to a commit.
319-
return new ThrowableHolder(ex);
321+
throwableHolder.throwable = ex;
322+
return null;
320323
}
321324
}
322325
finally {
@@ -325,17 +328,28 @@ public Object doInTransaction(TransactionStatus status) {
325328
}
326329
});
327330

328-
// Check result: It might indicate a Throwable to rethrow.
329-
if (result instanceof ThrowableHolder) {
330-
throw ((ThrowableHolder) result).getThrowable();
331-
}
332-
else {
333-
return result;
331+
// Check result state: It might indicate a Throwable to rethrow.
332+
if (throwableHolder.throwable != null) {
333+
throw throwableHolder.throwable;
334334
}
335+
return result;
335336
}
336337
catch (ThrowableHolderException ex) {
337338
throw ex.getCause();
338339
}
340+
catch (TransactionSystemException ex2) {
341+
if (throwableHolder.throwable != null) {
342+
logger.error("Application exception overridden by commit exception", throwableHolder.throwable);
343+
ex2.initApplicationException(throwableHolder.throwable);
344+
}
345+
throw ex2;
346+
}
347+
catch (Throwable ex2) {
348+
if (throwableHolder.throwable != null) {
349+
logger.error("Application exception overridden by commit exception", throwableHolder.throwable);
350+
}
351+
throw ex2;
352+
}
339353
}
340354
}
341355

@@ -657,20 +671,11 @@ protected interface InvocationCallback {
657671

658672

659673
/**
660-
* Internal holder class for a Throwable, used as a return value
661-
* from a TransactionCallback (to be subsequently unwrapped again).
674+
* Internal holder class for a Throwable in a callback transaction model.
662675
*/
663676
private static class ThrowableHolder {
664677

665-
private final Throwable throwable;
666-
667-
public ThrowableHolder(Throwable throwable) {
668-
this.throwable = throwable;
669-
}
670-
671-
public final Throwable getThrowable() {
672-
return this.throwable;
673-
}
678+
public Throwable throwable;
674679
}
675680

676681

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

Lines changed: 32 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2015 the original author or authors.
2+
* Copyright 2002-2017 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.
@@ -246,7 +246,8 @@ public <T> T execute(TransactionDefinition definition, TransactionCallback<T> ca
246246
"Transaction propagation 'nested' not supported for WebSphere UOW transactions");
247247
}
248248
if (pb == TransactionDefinition.PROPAGATION_SUPPORTS ||
249-
pb == TransactionDefinition.PROPAGATION_REQUIRED || pb == TransactionDefinition.PROPAGATION_MANDATORY) {
249+
pb == TransactionDefinition.PROPAGATION_REQUIRED ||
250+
pb == TransactionDefinition.PROPAGATION_MANDATORY) {
250251
joinTx = true;
251252
newSynch = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER);
252253
}
@@ -264,7 +265,8 @@ else if (pb == TransactionDefinition.PROPAGATION_NOT_SUPPORTED) {
264265
"Transaction propagation 'mandatory' but no existing transaction found");
265266
}
266267
if (pb == TransactionDefinition.PROPAGATION_SUPPORTS ||
267-
pb == TransactionDefinition.PROPAGATION_NOT_SUPPORTED || pb == TransactionDefinition.PROPAGATION_NEVER) {
268+
pb == TransactionDefinition.PROPAGATION_NOT_SUPPORTED ||
269+
pb == TransactionDefinition.PROPAGATION_NEVER) {
268270
uowType = UOWSynchronizationRegistry.UOW_TYPE_LOCAL_TRANSACTION;
269271
newSynch = (getTransactionSynchronization() == SYNCHRONIZATION_ALWAYS);
270272
}
@@ -278,14 +280,15 @@ else if (pb == TransactionDefinition.PROPAGATION_NOT_SUPPORTED) {
278280
logger.debug("Creating new transaction with name [" + definition.getName() + "]: " + definition);
279281
}
280282
SuspendedResourcesHolder suspendedResources = (!joinTx ? suspend(null) : null);
283+
UOWActionAdapter<T> action = null;
281284
try {
282285
if (definition.getTimeout() > TransactionDefinition.TIMEOUT_DEFAULT) {
283286
this.uowManager.setUOWTimeout(uowType, definition.getTimeout());
284287
}
285288
if (debug) {
286289
logger.debug("Invoking WebSphere UOW action: type=" + uowType + ", join=" + joinTx);
287290
}
288-
UOWActionAdapter<T> action = new UOWActionAdapter<T>(
291+
action = new UOWActionAdapter<T>(
289292
definition, callback, (uowType == UOWManager.UOW_TYPE_GLOBAL_TRANSACTION), !joinTx, newSynch, debug);
290293
this.uowManager.runUnderUOW(uowType, joinTx, action);
291294
if (debug) {
@@ -294,10 +297,24 @@ else if (pb == TransactionDefinition.PROPAGATION_NOT_SUPPORTED) {
294297
return action.getResult();
295298
}
296299
catch (UOWException ex) {
297-
throw new TransactionSystemException("UOWManager transaction processing failed", ex);
300+
TransactionSystemException tse =
301+
new TransactionSystemException("UOWManager transaction processing failed", ex);
302+
Throwable appEx = action.getException();
303+
if (appEx != null) {
304+
logger.error("Application exception overridden by rollback exception", appEx);
305+
tse.initApplicationException(appEx);
306+
}
307+
throw tse;
298308
}
299309
catch (UOWActionException ex) {
300-
throw new TransactionSystemException("UOWManager threw unexpected UOWActionException", ex);
310+
TransactionSystemException tse =
311+
new TransactionSystemException("UOWManager threw unexpected UOWActionException", ex);
312+
Throwable appEx = action.getException();
313+
if (appEx != null) {
314+
logger.error("Application exception overridden by rollback exception", appEx);
315+
tse.initApplicationException(appEx);
316+
}
317+
throw tse;
301318
}
302319
finally {
303320
if (suspendedResources != null) {
@@ -330,6 +347,7 @@ private class UOWActionAdapter<T> implements UOWAction, SmartTransactionObject {
330347

331348
public UOWActionAdapter(TransactionDefinition definition, TransactionCallback<T> callback,
332349
boolean actualTransaction, boolean newTransaction, boolean newSynchronization, boolean debug) {
350+
333351
this.definition = definition;
334352
this.callback = callback;
335353
this.actualTransaction = actualTransaction;
@@ -349,12 +367,15 @@ public void run() {
349367
}
350368
catch (Throwable ex) {
351369
this.exception = ex;
370+
if (status.isDebug()) {
371+
logger.debug("Rolling back on application exception from transaction callback", ex);
372+
}
352373
uowManager.setRollbackOnly();
353374
}
354375
finally {
355376
if (status.isLocalRollbackOnly()) {
356377
if (status.isDebug()) {
357-
logger.debug("Transactional code has requested rollback");
378+
logger.debug("Transaction callback has explicitly requested rollback");
358379
}
359380
uowManager.setRollbackOnly();
360381
}
@@ -376,6 +397,10 @@ public T getResult() {
376397
return this.result;
377398
}
378399

400+
public Throwable getException() {
401+
return this.exception;
402+
}
403+
379404
@Override
380405
public boolean isRollbackOnly() {
381406
return uowManager.getRollbackOnly();

0 commit comments

Comments
 (0)