diff --git a/spring-tx/src/main/java/org/springframework/transaction/interceptor/TransactionAspectSupport.java b/spring-tx/src/main/java/org/springframework/transaction/interceptor/TransactionAspectSupport.java index 78b4340d24..43663965cb 100644 --- a/spring-tx/src/main/java/org/springframework/transaction/interceptor/TransactionAspectSupport.java +++ b/spring-tx/src/main/java/org/springframework/transaction/interceptor/TransactionAspectSupport.java @@ -294,6 +294,8 @@ public abstract class TransactionAspectSupport implements BeanFactoryAware, Init } else { + final ThrowableHolder throwableHolder = new ThrowableHolder(); + // It's a CallbackPreferringPlatformTransactionManager: pass a TransactionCallback in. try { Object result = ((CallbackPreferringPlatformTransactionManager) tm).execute(txAttr, @@ -316,7 +318,8 @@ public abstract class TransactionAspectSupport implements BeanFactoryAware, Init } else { // A normal return value: will lead to a commit. - return new ThrowableHolder(ex); + throwableHolder.throwable = ex; + return null; } } finally { @@ -325,17 +328,28 @@ public abstract class TransactionAspectSupport implements BeanFactoryAware, Init } }); - // Check result: It might indicate a Throwable to rethrow. - if (result instanceof ThrowableHolder) { - throw ((ThrowableHolder) result).getThrowable(); - } - else { - return result; + // Check result state: It might indicate a Throwable to rethrow. + if (throwableHolder.throwable != null) { + throw throwableHolder.throwable; } + return result; } catch (ThrowableHolderException ex) { throw ex.getCause(); } + catch (TransactionSystemException ex2) { + if (throwableHolder.throwable != null) { + logger.error("Application exception overridden by commit exception", throwableHolder.throwable); + ex2.initApplicationException(throwableHolder.throwable); + } + throw ex2; + } + catch (Throwable ex2) { + if (throwableHolder.throwable != null) { + logger.error("Application exception overridden by commit exception", throwableHolder.throwable); + } + throw ex2; + } } } @@ -657,20 +671,11 @@ public abstract class TransactionAspectSupport implements BeanFactoryAware, Init /** - * Internal holder class for a Throwable, used as a return value - * from a TransactionCallback (to be subsequently unwrapped again). + * Internal holder class for a Throwable in a callback transaction model. */ private static class ThrowableHolder { - private final Throwable throwable; - - public ThrowableHolder(Throwable throwable) { - this.throwable = throwable; - } - - public final Throwable getThrowable() { - return this.throwable; - } + public Throwable throwable; } diff --git a/spring-tx/src/main/java/org/springframework/transaction/jta/WebSphereUowTransactionManager.java b/spring-tx/src/main/java/org/springframework/transaction/jta/WebSphereUowTransactionManager.java index 9b7a07a0f5..0be128bcfd 100644 --- a/spring-tx/src/main/java/org/springframework/transaction/jta/WebSphereUowTransactionManager.java +++ b/spring-tx/src/main/java/org/springframework/transaction/jta/WebSphereUowTransactionManager.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2015 the original author or authors. + * Copyright 2002-2017 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. @@ -246,7 +246,8 @@ public class WebSphereUowTransactionManager extends JtaTransactionManager "Transaction propagation 'nested' not supported for WebSphere UOW transactions"); } if (pb == TransactionDefinition.PROPAGATION_SUPPORTS || - pb == TransactionDefinition.PROPAGATION_REQUIRED || pb == TransactionDefinition.PROPAGATION_MANDATORY) { + pb == TransactionDefinition.PROPAGATION_REQUIRED || + pb == TransactionDefinition.PROPAGATION_MANDATORY) { joinTx = true; newSynch = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER); } @@ -264,7 +265,8 @@ public class WebSphereUowTransactionManager extends JtaTransactionManager "Transaction propagation 'mandatory' but no existing transaction found"); } if (pb == TransactionDefinition.PROPAGATION_SUPPORTS || - pb == TransactionDefinition.PROPAGATION_NOT_SUPPORTED || pb == TransactionDefinition.PROPAGATION_NEVER) { + pb == TransactionDefinition.PROPAGATION_NOT_SUPPORTED || + pb == TransactionDefinition.PROPAGATION_NEVER) { uowType = UOWSynchronizationRegistry.UOW_TYPE_LOCAL_TRANSACTION; newSynch = (getTransactionSynchronization() == SYNCHRONIZATION_ALWAYS); } @@ -278,6 +280,7 @@ public class WebSphereUowTransactionManager extends JtaTransactionManager logger.debug("Creating new transaction with name [" + definition.getName() + "]: " + definition); } SuspendedResourcesHolder suspendedResources = (!joinTx ? suspend(null) : null); + UOWActionAdapter action = null; try { if (definition.getTimeout() > TransactionDefinition.TIMEOUT_DEFAULT) { this.uowManager.setUOWTimeout(uowType, definition.getTimeout()); @@ -285,7 +288,7 @@ public class WebSphereUowTransactionManager extends JtaTransactionManager if (debug) { logger.debug("Invoking WebSphere UOW action: type=" + uowType + ", join=" + joinTx); } - UOWActionAdapter action = new UOWActionAdapter( + action = new UOWActionAdapter( definition, callback, (uowType == UOWManager.UOW_TYPE_GLOBAL_TRANSACTION), !joinTx, newSynch, debug); this.uowManager.runUnderUOW(uowType, joinTx, action); if (debug) { @@ -294,10 +297,24 @@ public class WebSphereUowTransactionManager extends JtaTransactionManager return action.getResult(); } catch (UOWException ex) { - throw new TransactionSystemException("UOWManager transaction processing failed", ex); + TransactionSystemException tse = + new TransactionSystemException("UOWManager transaction processing failed", ex); + Throwable appEx = action.getException(); + if (appEx != null) { + logger.error("Application exception overridden by rollback exception", appEx); + tse.initApplicationException(appEx); + } + throw tse; } catch (UOWActionException ex) { - throw new TransactionSystemException("UOWManager threw unexpected UOWActionException", ex); + TransactionSystemException tse = + new TransactionSystemException("UOWManager threw unexpected UOWActionException", ex); + Throwable appEx = action.getException(); + if (appEx != null) { + logger.error("Application exception overridden by rollback exception", appEx); + tse.initApplicationException(appEx); + } + throw tse; } finally { if (suspendedResources != null) { @@ -330,6 +347,7 @@ public class WebSphereUowTransactionManager extends JtaTransactionManager public UOWActionAdapter(TransactionDefinition definition, TransactionCallback callback, boolean actualTransaction, boolean newTransaction, boolean newSynchronization, boolean debug) { + this.definition = definition; this.callback = callback; this.actualTransaction = actualTransaction; @@ -349,12 +367,15 @@ public class WebSphereUowTransactionManager extends JtaTransactionManager } catch (Throwable ex) { this.exception = ex; + if (status.isDebug()) { + logger.debug("Rolling back on application exception from transaction callback", ex); + } uowManager.setRollbackOnly(); } finally { if (status.isLocalRollbackOnly()) { if (status.isDebug()) { - logger.debug("Transactional code has requested rollback"); + logger.debug("Transaction callback has explicitly requested rollback"); } uowManager.setRollbackOnly(); } @@ -376,6 +397,10 @@ public class WebSphereUowTransactionManager extends JtaTransactionManager return this.result; } + public Throwable getException() { + return this.exception; + } + @Override public boolean isRollbackOnly() { return uowManager.getRollbackOnly();