@Nullable all the way: null-safety at field level

This commits extends nullability declarations to the field level, formalizing the interaction between methods and their underlying fields and therefore avoiding any nullability mismatch.

Issue: SPR-15720
This commit is contained in:
Juergen Hoeller
2017-06-30 01:53:45 +02:00
parent c4694c3f5c
commit cc74a2891a
936 changed files with 6090 additions and 2806 deletions

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2013 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.
@@ -27,6 +27,7 @@ import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.BeanFactoryUtils;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.ListableBeanFactory;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.ReflectionUtils;
@@ -47,10 +48,12 @@ import org.springframework.util.ReflectionUtils;
public class PersistenceExceptionTranslationInterceptor
implements MethodInterceptor, BeanFactoryAware, InitializingBean {
@Nullable
private volatile PersistenceExceptionTranslator persistenceExceptionTranslator;
private boolean alwaysTranslate = false;
@Nullable
private ListableBeanFactory beanFactory;
@@ -141,10 +144,13 @@ public class PersistenceExceptionTranslationInterceptor
throw ex;
}
else {
if (this.persistenceExceptionTranslator == null) {
this.persistenceExceptionTranslator = detectPersistenceExceptionTranslators(this.beanFactory);
PersistenceExceptionTranslator translator = this.persistenceExceptionTranslator;
if (translator == null) {
Assert.state(this.beanFactory != null, "No PersistenceExceptionTranslator set");
translator = detectPersistenceExceptionTranslators(this.beanFactory);
this.persistenceExceptionTranslator = translator;
}
throw DataAccessUtils.translateIfNecessary(ex, this.persistenceExceptionTranslator);
throw DataAccessUtils.translateIfNecessary(ex, translator);
}
}
}

View File

@@ -66,6 +66,7 @@ import org.springframework.util.Assert;
public class CciLocalTransactionManager extends AbstractPlatformTransactionManager
implements ResourceTransactionManager, InitializingBean {
@Nullable
private ConnectionFactory connectionFactory;
@@ -273,6 +274,7 @@ public class CciLocalTransactionManager extends AbstractPlatformTransactionManag
*/
private static class CciLocalTransactionObject {
@Nullable
private ConnectionHolder connectionHolder;
public void setConnectionHolder(@Nullable ConnectionHolder connectionHolder) {

View File

@@ -57,9 +57,11 @@ public class SingleConnectionFactory extends DelegatingConnectionFactory impleme
protected final Log logger = LogFactory.getLog(getClass());
/** Wrapped Connection */
@Nullable
private Connection target;
/** Proxy Connection */
@Nullable
private Connection connection;
/** Synchronization monitor for the shared Connection */

View File

@@ -72,10 +72,13 @@ public class CciTemplate implements CciOperations {
private final Log logger = LogFactory.getLog(getClass());
@Nullable
private ConnectionFactory connectionFactory;
@Nullable
private ConnectionSpec connectionSpec;
@Nullable
private RecordCreator outputRecordCreator;
@@ -106,7 +109,9 @@ public class CciTemplate implements CciOperations {
*/
public CciTemplate(ConnectionFactory connectionFactory, @Nullable ConnectionSpec connectionSpec) {
setConnectionFactory(connectionFactory);
setConnectionSpec(connectionSpec);
if (connectionSpec != null) {
setConnectionSpec(connectionSpec);
}
afterPropertiesSet();
}
@@ -114,7 +119,7 @@ public class CciTemplate implements CciOperations {
/**
* Set the CCI ConnectionFactory to obtain Connections from.
*/
public void setConnectionFactory(@Nullable ConnectionFactory connectionFactory) {
public void setConnectionFactory(ConnectionFactory connectionFactory) {
this.connectionFactory = connectionFactory;
}
@@ -136,7 +141,7 @@ public class CciTemplate implements CciOperations {
* Set the CCI ConnectionSpec that this template instance is
* supposed to obtain Connections for.
*/
public void setConnectionSpec(@Nullable ConnectionSpec connectionSpec) {
public void setConnectionSpec(ConnectionSpec connectionSpec) {
this.connectionSpec = connectionSpec;
}
@@ -160,7 +165,7 @@ public class CciTemplate implements CciOperations {
* @see javax.resource.cci.Interaction#execute(javax.resource.cci.InteractionSpec, Record)
* @see javax.resource.cci.Interaction#execute(javax.resource.cci.InteractionSpec, Record, Record)
*/
public void setOutputRecordCreator(@Nullable RecordCreator creator) {
public void setOutputRecordCreator(RecordCreator creator) {
this.outputRecordCreator = creator;
}
@@ -189,10 +194,11 @@ public class CciTemplate implements CciOperations {
* @see #setConnectionSpec
*/
public CciTemplate getDerivedTemplate(ConnectionSpec connectionSpec) {
CciTemplate derived = new CciTemplate();
derived.setConnectionFactory(getConnectionFactory());
derived.setConnectionSpec(connectionSpec);
derived.setOutputRecordCreator(getOutputRecordCreator());
CciTemplate derived = new CciTemplate(obtainConnectionFactory(), connectionSpec);
RecordCreator recordCreator = getOutputRecordCreator();
if (recordCreator != null) {
derived.setOutputRecordCreator(recordCreator);
}
return derived;
}

View File

@@ -47,6 +47,7 @@ import org.springframework.util.Assert;
*/
public abstract class CciDaoSupport extends DaoSupport {
@Nullable
private CciTemplate cciTemplate;
@@ -77,7 +78,7 @@ public abstract class CciDaoSupport extends DaoSupport {
*/
@Nullable
public final ConnectionFactory getConnectionFactory() {
return this.cciTemplate.getConnectionFactory();
return (this.cciTemplate != null ? this.cciTemplate.getConnectionFactory() : null);
}
/**
@@ -92,6 +93,7 @@ public abstract class CciDaoSupport extends DaoSupport {
* Return the CciTemplate for this DAO,
* pre-initialized with the ConnectionFactory or set explicitly.
*/
@Nullable
public final CciTemplate getCciTemplate() {
return this.cciTemplate;
}
@@ -114,7 +116,9 @@ public abstract class CciDaoSupport extends DaoSupport {
* @see org.springframework.jca.cci.core.CciTemplate#getDerivedTemplate(javax.resource.cci.ConnectionSpec)
*/
protected final CciTemplate getCciTemplate(ConnectionSpec connectionSpec) {
return getCciTemplate().getDerivedTemplate(connectionSpec);
CciTemplate cciTemplate = getCciTemplate();
Assert.state(cciTemplate != null, "No CciTemplate set");
return cciTemplate.getDerivedTemplate(connectionSpec);
}
/**

View File

@@ -21,6 +21,7 @@ import javax.resource.cci.InteractionSpec;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.jca.cci.core.CciTemplate;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
/**
@@ -39,6 +40,7 @@ public abstract class EisOperation implements InitializingBean {
private CciTemplate cciTemplate = new CciTemplate();
@Nullable
private InteractionSpec interactionSpec;
@@ -76,6 +78,7 @@ public abstract class EisOperation implements InitializingBean {
/**
* Return the CCI InteractionSpec for this operation.
*/
@Nullable
public InteractionSpec getInteractionSpec() {
return this.interactionSpec;
}
@@ -86,7 +89,7 @@ public abstract class EisOperation implements InitializingBean {
this.cciTemplate.afterPropertiesSet();
if (this.interactionSpec == null) {
throw new IllegalArgumentException("interactionSpec is required");
throw new IllegalArgumentException("InteractionSpec is required");
}
}

View File

@@ -27,6 +27,7 @@ import org.springframework.dao.DataAccessException;
import org.springframework.jca.cci.core.RecordCreator;
import org.springframework.jca.cci.core.RecordExtractor;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
/**
* EIS operation object that expects mapped input and output objects,
@@ -88,8 +89,10 @@ public abstract class MappingRecordOperation extends EisOperation {
*/
@Nullable
public Object execute(Object inputObject) throws DataAccessException {
InteractionSpec interactionSpec = getInteractionSpec();
Assert.state(interactionSpec != null, "No InteractionSpec set");
return getCciTemplate().execute(
getInteractionSpec(), new RecordCreatorImpl(inputObject), new RecordExtractorImpl());
interactionSpec, new RecordCreatorImpl(inputObject), new RecordExtractorImpl());
}

View File

@@ -22,6 +22,7 @@ import javax.resource.cci.Record;
import org.springframework.dao.DataAccessException;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
/**
* EIS operation object that accepts a passed-in CCI input Record
@@ -48,6 +49,7 @@ public class SimpleRecordOperation extends EisOperation {
setInteractionSpec(interactionSpec);
}
/**
* Execute the CCI interaction encapsulated by this operation object.
* <p>This method will call CCI's {@code Interaction.execute} variant
@@ -59,7 +61,9 @@ public class SimpleRecordOperation extends EisOperation {
*/
@Nullable
public Record execute(Record inputRecord) throws DataAccessException {
return getCciTemplate().execute(getInteractionSpec(), inputRecord);
InteractionSpec interactionSpec = getInteractionSpec();
Assert.state(interactionSpec != null, "No InteractionSpec set");
return getCciTemplate().execute(interactionSpec, inputRecord);
}
/**
@@ -72,7 +76,9 @@ public class SimpleRecordOperation extends EisOperation {
* @see javax.resource.cci.Interaction#execute(javax.resource.cci.InteractionSpec, Record, Record)
*/
public void execute(Record inputRecord, Record outputRecord) throws DataAccessException {
getCciTemplate().execute(getInteractionSpec(), inputRecord, outputRecord);
InteractionSpec interactionSpec = getInteractionSpec();
Assert.state(interactionSpec != null, "No InteractionSpec set");
getCciTemplate().execute(interactionSpec, inputRecord, outputRecord);
}
}

View File

@@ -36,6 +36,7 @@ import org.springframework.lang.Nullable;
*/
class BootstrapContextAwareProcessor implements BeanPostProcessor {
@Nullable
private final BootstrapContext bootstrapContext;

View File

@@ -33,6 +33,7 @@ import org.springframework.beans.factory.BeanNameAware;
import org.springframework.lang.Nullable;
import org.springframework.transaction.jta.SimpleTransactionFactory;
import org.springframework.transaction.jta.TransactionFactory;
import org.springframework.util.Assert;
/**
* Abstract base implementation of the JCA 1.7
@@ -49,12 +50,15 @@ public abstract class AbstractMessageEndpointFactory implements MessageEndpointF
/** Logger available to subclasses */
protected final Log logger = LogFactory.getLog(getClass());
@Nullable
private TransactionFactory transactionFactory;
@Nullable
private String transactionName;
private int transactionTimeout = -1;
@Nullable
private String beanName;
@@ -201,10 +205,12 @@ public abstract class AbstractMessageEndpointFactory implements MessageEndpointF
*/
protected abstract class AbstractMessageEndpoint implements MessageEndpoint {
@Nullable
private TransactionDelegate transactionDelegate;
private boolean beforeDeliveryCalled = false;
@Nullable
private ClassLoader previousContextClassLoader;
/**
@@ -228,6 +234,7 @@ public abstract class AbstractMessageEndpointFactory implements MessageEndpointF
@Override
public void beforeDelivery(@Nullable Method method) throws ResourceException {
this.beforeDeliveryCalled = true;
Assert.state(this.transactionDelegate != null, "Not initialized");
try {
this.transactionDelegate.beginTransaction();
}
@@ -263,6 +270,7 @@ public abstract class AbstractMessageEndpointFactory implements MessageEndpointF
* @param ex the exception thrown from the concrete endpoint
*/
protected final void onEndpointException(Throwable ex) {
Assert.state(this.transactionDelegate != null, "Not initialized");
this.transactionDelegate.setRollbackOnly();
}
@@ -275,6 +283,7 @@ public abstract class AbstractMessageEndpointFactory implements MessageEndpointF
*/
@Override
public void afterDelivery() throws ResourceException {
Assert.state(this.transactionDelegate != null, "Not initialized");
this.beforeDeliveryCalled = false;
Thread.currentThread().setContextClassLoader(this.previousContextClassLoader);
this.previousContextClassLoader = null;
@@ -288,12 +297,14 @@ public abstract class AbstractMessageEndpointFactory implements MessageEndpointF
@Override
public void release() {
try {
this.transactionDelegate.setRollbackOnly();
this.transactionDelegate.endTransaction();
}
catch (Throwable ex) {
logger.error("Could not complete unfinished transaction on endpoint release", ex);
if (this.transactionDelegate != null) {
try {
this.transactionDelegate.setRollbackOnly();
this.transactionDelegate.endTransaction();
}
catch (Throwable ex) {
logger.error("Could not complete unfinished transaction on endpoint release", ex);
}
}
}
}
@@ -305,8 +316,10 @@ public abstract class AbstractMessageEndpointFactory implements MessageEndpointF
*/
private class TransactionDelegate {
@Nullable
private final XAResource xaResource;
@Nullable
private Transaction transaction;
private boolean rollbackOnly;

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2016 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.
@@ -22,6 +22,7 @@ import javax.resource.spi.ManagedConnectionFactory;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.lang.Nullable;
/**
* {@link org.springframework.beans.factory.FactoryBean} that creates
@@ -70,10 +71,13 @@ import org.springframework.beans.factory.InitializingBean;
*/
public class LocalConnectionFactoryBean implements FactoryBean<Object>, InitializingBean {
@Nullable
private ManagedConnectionFactory managedConnectionFactory;
@Nullable
private ConnectionManager connectionManager;
@Nullable
private Object connectionFactory;

View File

@@ -26,6 +26,7 @@ import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.lang.Nullable;
/**
* {@link org.springframework.beans.factory.FactoryBean} that bootstraps
@@ -49,12 +50,16 @@ import org.springframework.beans.factory.InitializingBean;
*/
public class ResourceAdapterFactoryBean implements FactoryBean<ResourceAdapter>, InitializingBean, DisposableBean {
@Nullable
private ResourceAdapter resourceAdapter;
@Nullable
private BootstrapContext bootstrapContext;
@Nullable
private WorkManager workManager;
@Nullable
private XATerminator xaTerminator;
@@ -145,7 +150,9 @@ public class ResourceAdapterFactoryBean implements FactoryBean<ResourceAdapter>,
*/
@Override
public void destroy() {
this.resourceAdapter.stop();
if (this.resourceAdapter != null) {
this.resourceAdapter.stop();
}
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2016 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.
@@ -17,7 +17,6 @@
package org.springframework.jca.support;
import java.util.Timer;
import javax.resource.spi.BootstrapContext;
import javax.resource.spi.UnavailableException;
import javax.resource.spi.XATerminator;
@@ -26,6 +25,7 @@ import javax.resource.spi.work.WorkManager;
import javax.transaction.TransactionSynchronizationRegistry;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
/**
* Simple implementation of the JCA 1.7 {@link javax.resource.spi.BootstrapContext}
@@ -41,10 +41,13 @@ import org.springframework.lang.Nullable;
*/
public class SimpleBootstrapContext implements BootstrapContext {
@Nullable
private WorkManager workManager;
@Nullable
private XATerminator xaTerminator;
@Nullable
private TransactionSynchronizationRegistry transactionSynchronizationRegistry;
@@ -87,13 +90,12 @@ public class SimpleBootstrapContext implements BootstrapContext {
@Override
public WorkManager getWorkManager() {
if (this.workManager == null) {
throw new IllegalStateException("No WorkManager available");
}
Assert.state(this.workManager != null, "No WorkManager available");
return this.workManager;
}
@Override
@Nullable
public XATerminator getXATerminator() {
return this.xaTerminator;
}
@@ -109,6 +111,7 @@ public class SimpleBootstrapContext implements BootstrapContext {
}
@Override
@Nullable
public TransactionSynchronizationRegistry getTransactionSynchronizationRegistry() {
return this.transactionSynchronizationRegistry;
}

View File

@@ -63,8 +63,10 @@ import org.springframework.util.Assert;
*/
public class SimpleTaskWorkManager implements WorkManager {
@Nullable
private TaskExecutor syncTaskExecutor = new SyncTaskExecutor();
@Nullable
private AsyncTaskExecutor asyncTaskExecutor = new SimpleAsyncTaskExecutor();
@@ -238,16 +240,11 @@ public class SimpleTaskWorkManager implements WorkManager {
try {
this.work.run();
}
catch (RuntimeException ex) {
catch (RuntimeException | Error ex) {
this.workListener.workCompleted(
new WorkEvent(this, WorkEvent.WORK_COMPLETED, this.work, new WorkCompletedException(ex)));
throw ex;
}
catch (Error err) {
this.workListener.workCompleted(
new WorkEvent(this, WorkEvent.WORK_COMPLETED, this.work, new WorkCompletedException(err)));
throw err;
}
this.workListener.workCompleted(new WorkEvent(this, WorkEvent.WORK_COMPLETED, this.work, null));
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2016 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.
@@ -70,16 +70,20 @@ import org.springframework.util.concurrent.ListenableFutureTask;
public class WorkManagerTaskExecutor extends JndiLocatorSupport
implements AsyncListenableTaskExecutor, SchedulingTaskExecutor, WorkManager, BootstrapContextAware, InitializingBean {
@Nullable
private WorkManager workManager;
@Nullable
private String workManagerName;
private boolean blockUntilStarted = false;
private boolean blockUntilCompleted = false;
@Nullable
private WorkListener workListener;
@Nullable
private TaskDecorator taskDecorator;
@@ -198,6 +202,11 @@ public class WorkManagerTaskExecutor extends JndiLocatorSupport
return new SimpleTaskWorkManager();
}
private WorkManager obtainWorkManager() {
Assert.state(this.workManager != null, "No WorkManager specified");
return this.workManager;
}
//-------------------------------------------------------------------------
// Implementation of the Spring SchedulingTaskExecutor interface
@@ -210,31 +219,30 @@ public class WorkManagerTaskExecutor extends JndiLocatorSupport
@Override
public void execute(Runnable task, long startTimeout) {
Assert.state(this.workManager != null, "No WorkManager specified");
Work work = new DelegatingWork(this.taskDecorator != null ? this.taskDecorator.decorate(task) : task);
try {
if (this.blockUntilCompleted) {
if (startTimeout != TIMEOUT_INDEFINITE || this.workListener != null) {
this.workManager.doWork(work, startTimeout, null, this.workListener);
obtainWorkManager().doWork(work, startTimeout, null, this.workListener);
}
else {
this.workManager.doWork(work);
obtainWorkManager().doWork(work);
}
}
else if (this.blockUntilStarted) {
if (startTimeout != TIMEOUT_INDEFINITE || this.workListener != null) {
this.workManager.startWork(work, startTimeout, null, this.workListener);
obtainWorkManager().startWork(work, startTimeout, null, this.workListener);
}
else {
this.workManager.startWork(work);
obtainWorkManager().startWork(work);
}
}
else {
if (startTimeout != TIMEOUT_INDEFINITE || this.workListener != null) {
this.workManager.scheduleWork(work, startTimeout, null, this.workListener);
obtainWorkManager().scheduleWork(work, startTimeout, null, this.workListener);
}
else {
this.workManager.scheduleWork(work);
obtainWorkManager().scheduleWork(work);
}
}
}
@@ -294,38 +302,38 @@ public class WorkManagerTaskExecutor extends JndiLocatorSupport
@Override
public void doWork(Work work) throws WorkException {
this.workManager.doWork(work);
obtainWorkManager().doWork(work);
}
@Override
public void doWork(Work work, long delay, ExecutionContext executionContext, WorkListener workListener)
throws WorkException {
this.workManager.doWork(work, delay, executionContext, workListener);
obtainWorkManager().doWork(work, delay, executionContext, workListener);
}
@Override
public long startWork(Work work) throws WorkException {
return this.workManager.startWork(work);
return obtainWorkManager().startWork(work);
}
@Override
public long startWork(Work work, long delay, ExecutionContext executionContext, WorkListener workListener)
throws WorkException {
return this.workManager.startWork(work, delay, executionContext, workListener);
return obtainWorkManager().startWork(work, delay, executionContext, workListener);
}
@Override
public void scheduleWork(Work work) throws WorkException {
this.workManager.scheduleWork(work);
obtainWorkManager().scheduleWork(work);
}
@Override
public void scheduleWork(Work work, long delay, ExecutionContext executionContext, WorkListener workListener)
throws WorkException {
this.workManager.scheduleWork(work, delay, executionContext, workListener);
obtainWorkManager().scheduleWork(work, delay, executionContext, workListener);
}
}

View File

@@ -29,6 +29,7 @@ import org.springframework.util.Assert;
@SuppressWarnings("serial")
public class TransactionSystemException extends TransactionException {
@Nullable
private Throwable applicationException;

View File

@@ -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.
@@ -26,6 +26,7 @@ import org.springframework.context.annotation.ImportAware;
import org.springframework.context.annotation.Role;
import org.springframework.core.annotation.AnnotationAttributes;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.lang.Nullable;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.config.TransactionManagementConfigUtils;
import org.springframework.transaction.event.TransactionalEventListenerFactory;
@@ -43,11 +44,13 @@ import org.springframework.util.CollectionUtils;
@Configuration
public abstract class AbstractTransactionManagementConfiguration implements ImportAware {
@Nullable
protected AnnotationAttributes enableTx;
/**
* Default transaction manager, as configured through a {@link TransactionManagementConfigurer}.
*/
@Nullable
protected PlatformTransactionManager txManager;

View File

@@ -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.
@@ -43,7 +43,9 @@ public class ProxyTransactionManagementConfiguration extends AbstractTransaction
BeanFactoryTransactionAttributeSourceAdvisor advisor = new BeanFactoryTransactionAttributeSourceAdvisor();
advisor.setTransactionAttributeSource(transactionAttributeSource());
advisor.setAdvice(transactionInterceptor());
advisor.setOrder(this.enableTx.<Integer>getNumber("order"));
if (this.enableTx != null) {
advisor.setOrder(this.enableTx.<Integer>getNumber("order"));
}
return advisor;
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2016 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.
@@ -18,6 +18,7 @@ package org.springframework.transaction.config;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.lang.Nullable;
import org.springframework.transaction.jta.JtaTransactionManager;
import org.springframework.util.ClassUtils;
@@ -50,6 +51,7 @@ public class JtaTransactionManagerFactoryBean implements FactoryBean<JtaTransact
"com.ibm.wsspi.uow.UOWManager", JtaTransactionManagerFactoryBean.class.getClassLoader());
@Nullable
private final JtaTransactionManager transactionManager;

View File

@@ -50,10 +50,11 @@ class ApplicationListenerMethodTransactionalAdapter extends ApplicationListenerM
public ApplicationListenerMethodTransactionalAdapter(String beanName, Class<?> targetClass, Method method) {
super(beanName, targetClass, method);
this.annotation = AnnotatedElementUtils.findMergedAnnotation(method, TransactionalEventListener.class);
if (this.annotation == null) {
TransactionalEventListener ann = AnnotatedElementUtils.findMergedAnnotation(method, TransactionalEventListener.class);
if (ann == null) {
throw new IllegalStateException("No TransactionalEventListener annotation found on method: " + method);
}
this.annotation = ann;
}

View File

@@ -30,8 +30,10 @@ import org.springframework.transaction.support.DefaultTransactionDefinition;
@SuppressWarnings("serial")
public class DefaultTransactionAttribute extends DefaultTransactionDefinition implements TransactionAttribute {
@Nullable
private String qualifier;
@Nullable
private String descriptor;

View File

@@ -50,8 +50,10 @@ public class MethodMapTransactionAttributeSource
protected final Log logger = LogFactory.getLog(getClass());
/** Map from method name to attribute value */
@Nullable
private Map<String, TransactionAttribute> methodMap;
@Nullable
private ClassLoader beanClassLoader = ClassUtils.getDefaultClassLoader();
private boolean eagerlyInitialized = false;

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2016 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.
@@ -24,6 +24,8 @@ import java.util.List;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.lang.Nullable;
/**
* TransactionAttribute implementation that works out whether a given exception
* should cause transaction rollback by applying a number of rollback rules,
@@ -50,6 +52,7 @@ public class RuleBasedTransactionAttribute extends DefaultTransactionAttribute i
/** Static for optimal serializability */
private static final Log logger = LogFactory.getLog(RuleBasedTransactionAttribute.class);
@Nullable
private List<RollbackRuleAttribute> rollbackRules;
@@ -78,7 +81,7 @@ public class RuleBasedTransactionAttribute extends DefaultTransactionAttribute i
*/
public RuleBasedTransactionAttribute(RuleBasedTransactionAttribute other) {
super(other);
this.rollbackRules = new ArrayList<>(other.rollbackRules);
this.rollbackRules = (other.rollbackRules != null ? new ArrayList<>(other.rollbackRules) : null);
}
/**

View File

@@ -129,12 +129,16 @@ public abstract class TransactionAspectSupport implements BeanFactoryAware, Init
protected final Log logger = LogFactory.getLog(getClass());
@Nullable
private String transactionManagerBeanName;
@Nullable
private PlatformTransactionManager transactionManager;
@Nullable
private TransactionAttributeSource transactionAttributeSource;
@Nullable
private BeanFactory beanFactory;
private final ConcurrentMap<Object, PlatformTransactionManager> transactionManagerCache =
@@ -151,6 +155,7 @@ public abstract class TransactionAspectSupport implements BeanFactoryAware, Init
/**
* Return the name of the default transaction manager bean.
*/
@Nullable
protected final String getTransactionManagerBeanName() {
return this.transactionManagerBeanName;
}
@@ -236,6 +241,7 @@ public abstract class TransactionAspectSupport implements BeanFactoryAware, Init
/**
* Return the BeanFactory to use for retrieving PlatformTransactionManager beans.
*/
@Nullable
protected final BeanFactory getBeanFactory() {
return this.beanFactory;
}
@@ -361,10 +367,10 @@ public abstract class TransactionAspectSupport implements BeanFactoryAware, Init
String qualifier = txAttr.getQualifier();
if (StringUtils.hasText(qualifier)) {
return determineQualifiedTransactionManager(qualifier);
return determineQualifiedTransactionManager(this.beanFactory, qualifier);
}
else if (StringUtils.hasText(this.transactionManagerBeanName)) {
return determineQualifiedTransactionManager(this.transactionManagerBeanName);
return determineQualifiedTransactionManager(this.beanFactory, this.transactionManagerBeanName);
}
else {
PlatformTransactionManager defaultTransactionManager = getTransactionManager();
@@ -380,11 +386,11 @@ public abstract class TransactionAspectSupport implements BeanFactoryAware, Init
}
}
private PlatformTransactionManager determineQualifiedTransactionManager(String qualifier) {
private PlatformTransactionManager determineQualifiedTransactionManager(BeanFactory beanFactory, String qualifier) {
PlatformTransactionManager txManager = this.transactionManagerCache.get(qualifier);
if (txManager == null) {
txManager = BeanFactoryAnnotationUtils.qualifiedBeanOfType(
this.beanFactory, PlatformTransactionManager.class, qualifier);
beanFactory, PlatformTransactionManager.class, qualifier);
this.transactionManagerCache.putIfAbsent(qualifier, txManager);
}
return txManager;
@@ -505,7 +511,7 @@ public abstract class TransactionAspectSupport implements BeanFactoryAware, Init
* @param txInfo information about the current transaction
*/
protected void commitTransactionAfterReturning(@Nullable TransactionInfo txInfo) {
if (txInfo != null && txInfo.hasTransaction()) {
if (txInfo != null && txInfo.getTransactionStatus() != null) {
if (logger.isTraceEnabled()) {
logger.trace("Completing transaction for [" + txInfo.getJoinpointIdentification() + "]");
}
@@ -520,7 +526,7 @@ public abstract class TransactionAspectSupport implements BeanFactoryAware, Init
* @param ex throwable encountered
*/
protected void completeTransactionAfterThrowing(@Nullable TransactionInfo txInfo, Throwable ex) {
if (txInfo != null && txInfo.hasTransaction()) {
if (txInfo != null && txInfo.getTransactionStatus() != null) {
if (logger.isTraceEnabled()) {
logger.trace("Completing transaction for [" + txInfo.getJoinpointIdentification() +
"] after exception: " + ex);
@@ -584,14 +590,18 @@ public abstract class TransactionAspectSupport implements BeanFactoryAware, Init
*/
protected final class TransactionInfo {
@Nullable
private final PlatformTransactionManager transactionManager;
@Nullable
private final TransactionAttribute transactionAttribute;
private final String joinpointIdentification;
@Nullable
private TransactionStatus transactionStatus;
@Nullable
private TransactionInfo oldTransactionInfo;
public TransactionInfo(@Nullable PlatformTransactionManager transactionManager,
@@ -624,6 +634,7 @@ public abstract class TransactionAspectSupport implements BeanFactoryAware, Init
this.transactionStatus = status;
}
@Nullable
public TransactionStatus getTransactionStatus() {
return this.transactionStatus;
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2012 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.
@@ -16,6 +16,7 @@
package org.springframework.transaction.interceptor;
import org.springframework.lang.Nullable;
import org.springframework.transaction.TransactionDefinition;
/**
@@ -36,6 +37,7 @@ public interface TransactionAttribute extends TransactionDefinition {
* <p>This may be used for choosing a corresponding transaction manager
* to process this specific transaction.
*/
@Nullable
String getQualifier();
/**

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2012 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.
@@ -21,6 +21,8 @@ import org.aopalliance.aop.Advice;
import org.springframework.aop.ClassFilter;
import org.springframework.aop.Pointcut;
import org.springframework.aop.support.AbstractPointcutAdvisor;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
/**
* Advisor driven by a {@link TransactionAttributeSource}, used to include
@@ -38,6 +40,7 @@ import org.springframework.aop.support.AbstractPointcutAdvisor;
@SuppressWarnings("serial")
public class TransactionAttributeSourceAdvisor extends AbstractPointcutAdvisor {
@Nullable
private TransactionInterceptor transactionInterceptor;
private final TransactionAttributeSourcePointcut pointcut = new TransactionAttributeSourcePointcut() {
@@ -81,6 +84,7 @@ public class TransactionAttributeSourceAdvisor extends AbstractPointcutAdvisor {
@Override
public Advice getAdvice() {
Assert.state(this.transactionInterceptor != null, "No TransactionInterceptor set");
return this.transactionInterceptor;
}

View File

@@ -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.
@@ -26,6 +26,7 @@ import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.ListableBeanFactory;
import org.springframework.lang.Nullable;
import org.springframework.transaction.PlatformTransactionManager;
/**
@@ -117,6 +118,7 @@ public class TransactionProxyFactoryBean extends AbstractSingletonProxyFactoryBe
private final TransactionInterceptor transactionInterceptor = new TransactionInterceptor();
@Nullable
private Pointcut pointcut;

View File

@@ -149,8 +149,10 @@ public class JtaTransactionManager extends AbstractPlatformTransactionManager
private transient JndiTemplate jndiTemplate = new JndiTemplate();
@Nullable
private transient UserTransaction userTransaction;
@Nullable
private String userTransactionName;
private boolean autodetectUserTransaction = true;
@@ -159,14 +161,18 @@ public class JtaTransactionManager extends AbstractPlatformTransactionManager
private boolean userTransactionObtainedFromJndi = false;
@Nullable
private transient TransactionManager transactionManager;
@Nullable
private String transactionManagerName;
private boolean autodetectTransactionManager = true;
@Nullable
private transient TransactionSynchronizationRegistry transactionSynchronizationRegistry;
@Nullable
private String transactionSynchronizationRegistryName;
private boolean autodetectTransactionSynchronizationRegistry = true;
@@ -743,8 +749,8 @@ public class JtaTransactionManager extends AbstractPlatformTransactionManager
* @throws TransactionSystemException in case of errors
*/
@Nullable
protected TransactionSynchronizationRegistry findTransactionSynchronizationRegistry(UserTransaction ut, TransactionManager tm)
throws TransactionSystemException {
protected TransactionSynchronizationRegistry findTransactionSynchronizationRegistry(
@Nullable UserTransaction ut, @Nullable TransactionManager tm) throws TransactionSystemException {
if (this.userTransactionObtainedFromJndi) {
// UserTransaction has already been obtained from JNDI, so the

View File

@@ -49,6 +49,7 @@ public class SpringJtaSynchronizationAdapter implements Synchronization {
private final TransactionSynchronization springSynchronization;
@Nullable
private UserTransaction jtaTransaction;
private boolean beforeCompletionCalled = false;

View File

@@ -88,16 +88,21 @@ public class WebLogicJtaTransactionManager extends JtaTransactionManager {
private boolean weblogicUserTransactionAvailable;
@Nullable
private Method beginWithNameMethod;
@Nullable
private Method beginWithNameAndTimeoutMethod;
private boolean weblogicTransactionManagerAvailable;
@Nullable
private Method forceResumeMethod;
@Nullable
private Method setPropertyMethod;
@Nullable
private Object transactionHelper;
@@ -109,10 +114,10 @@ public class WebLogicJtaTransactionManager extends JtaTransactionManager {
@Override
protected UserTransaction retrieveUserTransaction() throws TransactionSystemException {
loadWebLogicTransactionHelper();
Object helper = loadWebLogicTransactionHelper();
try {
logger.debug("Retrieving JTA UserTransaction from WebLogic TransactionHelper");
Method getUserTransactionMethod = this.transactionHelper.getClass().getMethod("getUserTransaction");
Method getUserTransactionMethod = helper.getClass().getMethod("getUserTransaction");
return (UserTransaction) getUserTransactionMethod.invoke(this.transactionHelper);
}
catch (InvocationTargetException ex) {
@@ -127,10 +132,10 @@ public class WebLogicJtaTransactionManager extends JtaTransactionManager {
@Override
protected TransactionManager retrieveTransactionManager() throws TransactionSystemException {
loadWebLogicTransactionHelper();
Object helper = loadWebLogicTransactionHelper();
try {
logger.debug("Retrieving JTA TransactionManager from WebLogic TransactionHelper");
Method getTransactionManagerMethod = this.transactionHelper.getClass().getMethod("getTransactionManager");
Method getTransactionManagerMethod = helper.getClass().getMethod("getTransactionManager");
return (TransactionManager) getTransactionManagerMethod.invoke(this.transactionHelper);
}
catch (InvocationTargetException ex) {
@@ -143,12 +148,14 @@ public class WebLogicJtaTransactionManager extends JtaTransactionManager {
}
}
private void loadWebLogicTransactionHelper() throws TransactionSystemException {
if (this.transactionHelper == null) {
private Object loadWebLogicTransactionHelper() throws TransactionSystemException {
Object helper = this.transactionHelper;
if (helper == null) {
try {
Class<?> transactionHelperClass = getClass().getClassLoader().loadClass(TRANSACTION_HELPER_CLASS_NAME);
Method getTransactionHelperMethod = transactionHelperClass.getMethod("getTransactionHelper");
this.transactionHelper = getTransactionHelperMethod.invoke(null);
helper = getTransactionHelperMethod.invoke(null);
this.transactionHelper = helper;
logger.debug("WebLogic TransactionHelper found");
}
catch (InvocationTargetException ex) {
@@ -161,6 +168,7 @@ public class WebLogicJtaTransactionManager extends JtaTransactionManager {
ex);
}
}
return helper;
}
private void loadWebLogicTransactionClasses() throws TransactionSystemException {
@@ -220,6 +228,7 @@ public class WebLogicJtaTransactionManager extends JtaTransactionManager {
weblogic.transaction.UserTransaction wut = (weblogic.transaction.UserTransaction) ut;
wut.begin(definition.getName(), timeout);
*/
Assert.state(this.beginWithNameAndTimeoutMethod != null, "WebLogic JTA API not initialized");
this.beginWithNameAndTimeoutMethod.invoke(txObject.getUserTransaction(), definition.getName(), timeout);
}
else {
@@ -227,6 +236,7 @@ public class WebLogicJtaTransactionManager extends JtaTransactionManager {
weblogic.transaction.UserTransaction wut = (weblogic.transaction.UserTransaction) ut;
wut.begin(definition.getName());
*/
Assert.state(this.beginWithNameMethod != null, "WebLogic JTA API not initialized");
this.beginWithNameMethod.invoke(txObject.getUserTransaction(), definition.getName());
}
}
@@ -256,6 +266,7 @@ public class WebLogicJtaTransactionManager extends JtaTransactionManager {
weblogic.transaction.Transaction wtx = (weblogic.transaction.Transaction) tx;
wtx.setProperty(ISOLATION_LEVEL_KEY, isolationLevel);
*/
Assert.state(this.setPropertyMethod != null, "WebLogic JTA API not initialized");
this.setPropertyMethod.invoke(tx, ISOLATION_LEVEL_KEY, isolationLevel);
}
catch (InvocationTargetException ex) {
@@ -274,7 +285,7 @@ public class WebLogicJtaTransactionManager extends JtaTransactionManager {
}
@Override
protected void doJtaResume(JtaTransactionObject txObject, Object suspendedTransaction)
protected void doJtaResume(@Nullable JtaTransactionObject txObject, Object suspendedTransaction)
throws InvalidTransactionException, SystemException {
try {
@@ -295,6 +306,7 @@ public class WebLogicJtaTransactionManager extends JtaTransactionManager {
wtm.forceResume(suspendedTransaction);
*/
try {
Assert.state(this.forceResumeMethod != null, "WebLogic JTA API not initialized");
this.forceResumeMethod.invoke(getTransactionManager(), suspendedTransaction);
}
catch (InvocationTargetException ex2) {
@@ -313,9 +325,11 @@ public class WebLogicJtaTransactionManager extends JtaTransactionManager {
if (this.weblogicUserTransactionAvailable && name != null) {
try {
if (timeout >= 0) {
Assert.state(this.beginWithNameAndTimeoutMethod != null, "WebLogic JTA API not initialized");
this.beginWithNameAndTimeoutMethod.invoke(getUserTransaction(), name, timeout);
}
else {
Assert.state(this.beginWithNameMethod != null, "WebLogic JTA API not initialized");
this.beginWithNameMethod.invoke(getUserTransaction(), name);
}
}

View File

@@ -41,6 +41,7 @@ import org.springframework.transaction.support.TransactionCallback;
import org.springframework.transaction.support.TransactionSynchronization;
import org.springframework.transaction.support.TransactionSynchronizationManager;
import org.springframework.transaction.support.TransactionSynchronizationUtils;
import org.springframework.util.Assert;
import org.springframework.util.ReflectionUtils;
/**
@@ -96,8 +97,10 @@ public class WebSphereUowTransactionManager extends JtaTransactionManager
public static final String DEFAULT_UOW_MANAGER_NAME = "java:comp/websphere/UOWManager";
@Nullable
private UOWManager uowManager;
@Nullable
private String uowManagerName;
@@ -194,6 +197,12 @@ public class WebSphereUowTransactionManager extends JtaTransactionManager
}
}
private UOWManager obtainUOWManager() {
Assert.state(this.uowManager != null, "No UOWManager set");
return this.uowManager;
}
/**
* Registers the synchronizations as interposed JTA Synchronization on the UOWManager.
*/
@@ -201,7 +210,7 @@ public class WebSphereUowTransactionManager extends JtaTransactionManager
protected void doRegisterAfterCompletionWithJtaTransaction(
JtaTransactionObject txObject, List<TransactionSynchronization> synchronizations) {
this.uowManager.registerInterposedSynchronization(new JtaAfterCompletionSynchronization(synchronizations));
obtainUOWManager().registerInterposedSynchronization(new JtaAfterCompletionSynchronization(synchronizations));
}
/**
@@ -231,9 +240,11 @@ public class WebSphereUowTransactionManager extends JtaTransactionManager
if (definition.getTimeout() < TransactionDefinition.TIMEOUT_DEFAULT) {
throw new InvalidTimeoutException("Invalid transaction timeout", definition.getTimeout());
}
UOWManager uowManager = obtainUOWManager();
int pb = definition.getPropagationBehavior();
boolean existingTx = (this.uowManager.getUOWStatus() != UOWSynchronizationRegistry.UOW_STATUS_NONE &&
this.uowManager.getUOWType() != UOWSynchronizationRegistry.UOW_TYPE_LOCAL_TRANSACTION);
boolean existingTx = (uowManager.getUOWStatus() != UOWSynchronizationRegistry.UOW_STATUS_NONE &&
uowManager.getUOWType() != UOWSynchronizationRegistry.UOW_TYPE_LOCAL_TRANSACTION);
int uowType = UOWSynchronizationRegistry.UOW_TYPE_GLOBAL_TRANSACTION;
boolean joinTx = false;
@@ -283,14 +294,14 @@ public class WebSphereUowTransactionManager extends JtaTransactionManager
SuspendedResourcesHolder suspendedResources = (!joinTx ? suspend(null) : null);
try {
if (definition.getTimeout() > TransactionDefinition.TIMEOUT_DEFAULT) {
this.uowManager.setUOWTimeout(uowType, definition.getTimeout());
uowManager.setUOWTimeout(uowType, definition.getTimeout());
}
if (debug) {
logger.debug("Invoking WebSphere UOW action: type=" + uowType + ", join=" + joinTx);
}
UOWActionAdapter<T> action = new UOWActionAdapter<>(
definition, callback, (uowType == UOWManager.UOW_TYPE_GLOBAL_TRANSACTION), !joinTx, newSynch, debug);
this.uowManager.runUnderUOW(uowType, joinTx, action);
uowManager.runUnderUOW(uowType, joinTx, action);
if (debug) {
logger.debug("Returned from WebSphere UOW action: type=" + uowType + ", join=" + joinTx);
}
@@ -327,12 +338,15 @@ public class WebSphereUowTransactionManager extends JtaTransactionManager
private boolean debug;
@Nullable
private T result;
@Nullable
private Throwable exception;
public UOWActionAdapter(TransactionDefinition definition, TransactionCallback<T> callback,
boolean actualTransaction, boolean newTransaction, boolean newSynchronization, boolean debug) {
this.definition = definition;
this.callback = callback;
this.actualTransaction = actualTransaction;
@@ -343,6 +357,7 @@ public class WebSphereUowTransactionManager extends JtaTransactionManager
@Override
public void run() {
UOWManager uowManager = obtainUOWManager();
DefaultTransactionStatus status = prepareTransactionStatus(
this.definition, (this.actualTransaction ? this : null),
this.newTransaction, this.newSynchronization, this.debug, null);
@@ -372,6 +387,7 @@ public class WebSphereUowTransactionManager extends JtaTransactionManager
}
}
@Nullable
public T getResult() {
if (this.exception != null) {
ReflectionUtils.rethrowRuntimeException(this.exception);
@@ -381,7 +397,7 @@ public class WebSphereUowTransactionManager extends JtaTransactionManager
@Override
public boolean isRollbackOnly() {
return uowManager.getRollbackOnly();
return obtainUOWManager().getRollbackOnly();
}
@Override

View File

@@ -1271,14 +1271,18 @@ public abstract class AbstractPlatformTransactionManager implements PlatformTran
*/
protected static class SuspendedResourcesHolder {
@Nullable
private final Object suspendedResources;
@Nullable
private List<TransactionSynchronization> suspendedSynchronizations;
@Nullable
private String name;
private boolean readOnly;
@Nullable
private Integer isolationLevel;
private boolean wasActive;

View File

@@ -50,6 +50,7 @@ public abstract class AbstractTransactionStatus implements TransactionStatus {
private boolean completed = false;
@Nullable
private Object savepoint;

View File

@@ -19,6 +19,7 @@ package org.springframework.transaction.support;
import java.io.Serializable;
import org.springframework.core.Constants;
import org.springframework.lang.Nullable;
import org.springframework.transaction.TransactionDefinition;
/**
@@ -59,6 +60,7 @@ public class DefaultTransactionDefinition implements TransactionDefinition, Seri
private boolean readOnly = false;
@Nullable
private String name;

View File

@@ -50,6 +50,7 @@ import org.springframework.util.Assert;
*/
public class DefaultTransactionStatus extends AbstractTransactionStatus {
@Nullable
private final Object transaction;
private final boolean newTransaction;
@@ -60,6 +61,7 @@ public class DefaultTransactionStatus extends AbstractTransactionStatus {
private final boolean debug;
@Nullable
private final Object suspendedResources;

View File

@@ -18,6 +18,7 @@ package org.springframework.transaction.support;
import java.util.Date;
import org.springframework.lang.Nullable;
import org.springframework.transaction.TransactionTimedOutException;
/**
@@ -38,6 +39,7 @@ public abstract class ResourceHolderSupport implements ResourceHolder {
private boolean rollbackOnly = false;
@Nullable
private Date deadline;
private int referenceCount = 0;
@@ -111,6 +113,7 @@ public abstract class ResourceHolderSupport implements ResourceHolder {
* Return the expiration deadline of this object.
* @return the deadline as Date object
*/
@Nullable
public Date getDeadline() {
return this.deadline;
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2016 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.
@@ -22,11 +22,13 @@ import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.lang.Nullable;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionException;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.TransactionSystemException;
import org.springframework.util.Assert;
/**
* Template class that simplifies programmatic transaction demarcation and
@@ -66,6 +68,7 @@ public class TransactionTemplate extends DefaultTransactionDefinition
/** Logger available to subclasses */
protected final Log logger = LogFactory.getLog(getClass());
@Nullable
private PlatformTransactionManager transactionManager;
@@ -109,6 +112,7 @@ public class TransactionTemplate extends DefaultTransactionDefinition
/**
* Return the transaction management strategy to be used.
*/
@Nullable
public PlatformTransactionManager getTransactionManager() {
return this.transactionManager;
}
@@ -123,6 +127,8 @@ public class TransactionTemplate extends DefaultTransactionDefinition
@Override
public <T> T execute(TransactionCallback<T> action) throws TransactionException {
Assert.state(this.transactionManager != null, "No PlatformTransactionManager set");
if (this.transactionManager instanceof CallbackPreferringPlatformTransactionManager) {
return ((CallbackPreferringPlatformTransactionManager) this.transactionManager).execute(this, action);
}
@@ -132,16 +138,11 @@ public class TransactionTemplate extends DefaultTransactionDefinition
try {
result = action.doInTransaction(status);
}
catch (RuntimeException ex) {
catch (RuntimeException | Error ex) {
// Transactional code threw application exception -> rollback
rollbackOnException(status, ex);
throw ex;
}
catch (Error err) {
// Transactional code threw error -> rollback
rollbackOnException(status, err);
throw err;
}
catch (Throwable ex) {
// Transactional code threw unexpected exception -> rollback
rollbackOnException(status, ex);
@@ -159,6 +160,8 @@ public class TransactionTemplate extends DefaultTransactionDefinition
* @throws TransactionException in case of a rollback error
*/
private void rollbackOnException(TransactionStatus status, Throwable ex) throws TransactionException {
Assert.state(this.transactionManager != null, "No PlatformTransactionManager set");
logger.debug("Initiating transaction rollback on application exception", ex);
try {
this.transactionManager.rollback(status);