diff --git a/spring-test/src/main/java/org/springframework/test/context/transaction/TransactionConfiguration.java b/spring-test/src/main/java/org/springframework/test/context/transaction/TransactionConfiguration.java
index e62317b783..7d91bcba02 100644
--- a/spring-test/src/main/java/org/springframework/test/context/transaction/TransactionConfiguration.java
+++ b/spring-test/src/main/java/org/springframework/test/context/transaction/TransactionConfiguration.java
@@ -40,12 +40,19 @@ public @interface TransactionConfiguration {
/**
* The bean name of the {@link org.springframework.transaction.PlatformTransactionManager
- * PlatformTransactionManager} that is to be used to drive transactions.
+ * PlatformTransactionManager} that should be used to drive transactions.
*
- *
This attribute is not required and only needs to be specified explicitly
- * if there are multiple beans of type {@code PlatformTransactionManager} in
- * the test's {@code ApplicationContext} and the bean name of the desired
- * {@code PlatformTransactionManager} is not "transactionManager".
+ *
This attribute is not required and only needs to be declared if there
+ * are multiple beans of type {@code PlatformTransactionManager} in the test's
+ * {@code ApplicationContext} and if one of the following is true.
+ *
+ * - the bean name of the desired {@code PlatformTransactionManager} is not
+ * "transactionManager"
+ * - {@link org.springframework.transaction.annotation.TransactionManagementConfigurer
+ * TransactionManagementConfigurer} was not implemented to specify which
+ * {@code PlatformTransactionManager} bean should be used for annotation-driven
+ * transaction management
+ *
*
* NOTE: The XML {@code } element also refers
* to a bean named "transactionManager" by default. If you are using both
diff --git a/spring-test/src/main/java/org/springframework/test/context/transaction/TransactionalTestExecutionListener.java b/spring-test/src/main/java/org/springframework/test/context/transaction/TransactionalTestExecutionListener.java
index e182259ba7..9b1c529321 100644
--- a/spring-test/src/main/java/org/springframework/test/context/transaction/TransactionalTestExecutionListener.java
+++ b/spring-test/src/main/java/org/springframework/test/context/transaction/TransactionalTestExecutionListener.java
@@ -43,6 +43,7 @@ import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionException;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.annotation.AnnotationTransactionAttributeSource;
+import org.springframework.transaction.annotation.TransactionManagementConfigurer;
import org.springframework.transaction.interceptor.DelegatingTransactionAttribute;
import org.springframework.transaction.interceptor.TransactionAttribute;
import org.springframework.transaction.interceptor.TransactionAttributeSource;
@@ -68,11 +69,15 @@ import org.springframework.util.StringUtils;
*
* Transactional commit and rollback behavior can be configured via the
* class-level {@link TransactionConfiguration @TransactionConfiguration} and
- * method-level {@link Rollback @Rollback} annotations. In case there are multiple
- * instances of {@code PlatformTransactionManager} within the test's
- * {@code ApplicationContext}, {@code @TransactionConfiguration} supports
- * configuring the bean name of the {@code PlatformTransactionManager} that is
- * to be used to drive transactions.
+ * method-level {@link Rollback @Rollback} annotations.
+ *
+ *
In case there are multiple instances of {@code PlatformTransactionManager}
+ * within the test's {@code ApplicationContext}, @{@code TransactionConfiguration}
+ * supports configuring the bean name of the {@code PlatformTransactionManager}
+ * that should be used to drive transactions. Alternatively,
+ * {@link TransactionManagementConfigurer} can be implemented in an
+ * {@link org.springframework.context.annotation.Configuration @Configuration}
+ * class.
*
*
When executing transactional tests, it is sometimes useful to be able to
* execute certain set up or tear down code outside of a
@@ -349,13 +354,25 @@ public class TransactionalTestExecutionListener extends AbstractTestExecutionLis
return bf.getBean(tmName, PlatformTransactionManager.class);
}
- // look up single bean by type
if (bf instanceof ListableBeanFactory) {
ListableBeanFactory lbf = (ListableBeanFactory) bf;
- Map beansOfType = BeanFactoryUtils.beansOfTypeIncludingAncestors(
+
+ // look up single bean by type
+ Map txMgrs = BeanFactoryUtils.beansOfTypeIncludingAncestors(
lbf, PlatformTransactionManager.class);
- if (beansOfType.size() == 1) {
- return beansOfType.values().iterator().next();
+ if (txMgrs.size() == 1) {
+ return txMgrs.values().iterator().next();
+ }
+
+ // look up single TransactionManagementConfigurer
+ Map configurers = BeanFactoryUtils.beansOfTypeIncludingAncestors(
+ lbf, TransactionManagementConfigurer.class);
+ if (configurers.size() > 1) {
+ throw new IllegalStateException(
+ "Only one TransactionManagementConfigurer may exist in the ApplicationContext");
+ }
+ if (configurers.size() == 1) {
+ return configurers.values().iterator().next().annotationDrivenTransactionManager();
}
}
diff --git a/spring-test/src/test/java/org/springframework/test/context/junit4/spr9604/LookUpTxMgrViaTransactionManagementConfigurerTests.java b/spring-test/src/test/java/org/springframework/test/context/junit4/spr9604/LookUpTxMgrViaTransactionManagementConfigurerTests.java
new file mode 100644
index 0000000000..de9e21b2e3
--- /dev/null
+++ b/spring-test/src/test/java/org/springframework/test/context/junit4/spr9604/LookUpTxMgrViaTransactionManagementConfigurerTests.java
@@ -0,0 +1,101 @@
+/*
+ * Copyright 2002-2012 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.test.context.junit4.spr9604;
+
+import static org.junit.Assert.*;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.test.context.ContextConfiguration;
+import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
+import org.springframework.test.context.transaction.AfterTransaction;
+import org.springframework.test.context.transaction.BeforeTransaction;
+import org.springframework.test.transaction.CallCountingTransactionManager;
+import org.springframework.transaction.PlatformTransactionManager;
+import org.springframework.transaction.annotation.TransactionManagementConfigurer;
+import org.springframework.transaction.annotation.Transactional;
+
+/**
+ * Integration tests that verify the behavior requested in
+ * SPR-9604.
+ *
+ * @author Sam Brannen
+ * @since 3.2
+ */
+@RunWith(SpringJUnit4ClassRunner.class)
+@ContextConfiguration
+@Transactional
+public class LookUpTxMgrViaTransactionManagementConfigurerTests {
+
+ private static final CallCountingTransactionManager txManager1 = new CallCountingTransactionManager();
+ private static final CallCountingTransactionManager txManager2 = new CallCountingTransactionManager();
+
+
+ @Configuration
+ static class Config implements TransactionManagementConfigurer {
+
+ public PlatformTransactionManager annotationDrivenTransactionManager() {
+ return txManager1();
+ }
+
+ @Bean
+ public PlatformTransactionManager txManager1() {
+ return txManager1;
+ }
+
+ @Bean
+ public PlatformTransactionManager txManager2() {
+ return txManager2;
+ }
+ }
+
+
+ @BeforeTransaction
+ public void beforeTransaction() {
+ txManager1.clear();
+ txManager2.clear();
+ }
+
+ @Test
+ public void transactionalTest() {
+ assertEquals(1, txManager1.begun);
+ assertEquals(1, txManager1.inflight);
+ assertEquals(0, txManager1.commits);
+ assertEquals(0, txManager1.rollbacks);
+
+ assertEquals(0, txManager2.begun);
+ assertEquals(0, txManager2.inflight);
+ assertEquals(0, txManager2.commits);
+ assertEquals(0, txManager2.rollbacks);
+ }
+
+ @AfterTransaction
+ public void afterTransaction() {
+ assertEquals(1, txManager1.begun);
+ assertEquals(0, txManager1.inflight);
+ assertEquals(0, txManager1.commits);
+ assertEquals(1, txManager1.rollbacks);
+
+ assertEquals(0, txManager2.begun);
+ assertEquals(0, txManager2.inflight);
+ assertEquals(0, txManager2.commits);
+ assertEquals(0, txManager2.rollbacks);
+ }
+
+}
diff --git a/spring-test/src/test/java/org/springframework/test/context/junit4/spr9645/LookUpNonexistentTxMgrTests.java b/spring-test/src/test/java/org/springframework/test/context/junit4/spr9645/LookUpNonexistentTxMgrTests.java
index 0a70b0d0a2..72af7e7a7b 100644
--- a/spring-test/src/test/java/org/springframework/test/context/junit4/spr9645/LookUpNonexistentTxMgrTests.java
+++ b/spring-test/src/test/java/org/springframework/test/context/junit4/spr9645/LookUpNonexistentTxMgrTests.java
@@ -24,8 +24,6 @@ import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
-import org.springframework.test.context.transaction.AfterTransaction;
-import org.springframework.test.context.transaction.BeforeTransaction;
import org.springframework.test.transaction.CallCountingTransactionManager;
import org.springframework.transaction.PlatformTransactionManager;
@@ -42,7 +40,6 @@ public class LookUpNonexistentTxMgrTests {
private static final CallCountingTransactionManager txManager = new CallCountingTransactionManager();
-
@Configuration
static class Config {
@@ -52,26 +49,11 @@ public class LookUpNonexistentTxMgrTests {
}
}
-
- @BeforeTransaction
- public void beforeTransaction() {
- txManager.clear();
- }
-
@Test
- public void lookUpNothing() {
+ public void nonTransactionalTest() {
assertEquals(0, txManager.begun);
assertEquals(0, txManager.inflight);
assertEquals(0, txManager.commits);
assertEquals(0, txManager.rollbacks);
}
-
- @AfterTransaction
- public void afterTransaction() {
- assertEquals(0, txManager.begun);
- assertEquals(0, txManager.inflight);
- assertEquals(0, txManager.commits);
- assertEquals(0, txManager.rollbacks);
- }
-
}
diff --git a/spring-test/src/test/java/org/springframework/test/context/junit4/spr9645/LookUpTxMgrByTypeAndDefaultNameTests.java b/spring-test/src/test/java/org/springframework/test/context/junit4/spr9645/LookUpTxMgrByTypeAndDefaultNameTests.java
index 5cfdebaba3..6f1525229f 100644
--- a/spring-test/src/test/java/org/springframework/test/context/junit4/spr9645/LookUpTxMgrByTypeAndDefaultNameTests.java
+++ b/spring-test/src/test/java/org/springframework/test/context/junit4/spr9645/LookUpTxMgrByTypeAndDefaultNameTests.java
@@ -66,7 +66,7 @@ public class LookUpTxMgrByTypeAndDefaultNameTests {
}
@Test
- public void lookUpByTypeAndDefaultName() {
+ public void transactionalTest() {
assertEquals(1, txManager1.begun);
assertEquals(1, txManager1.inflight);
assertEquals(0, txManager1.commits);
diff --git a/spring-test/src/test/java/org/springframework/test/context/junit4/spr9645/LookUpTxMgrByTypeAndNameTests.java b/spring-test/src/test/java/org/springframework/test/context/junit4/spr9645/LookUpTxMgrByTypeAndNameTests.java
index 805243f11c..d8c070c504 100644
--- a/spring-test/src/test/java/org/springframework/test/context/junit4/spr9645/LookUpTxMgrByTypeAndNameTests.java
+++ b/spring-test/src/test/java/org/springframework/test/context/junit4/spr9645/LookUpTxMgrByTypeAndNameTests.java
@@ -68,7 +68,7 @@ public class LookUpTxMgrByTypeAndNameTests {
}
@Test
- public void lookUpByTypeAndName() {
+ public void transactionalTest() {
assertEquals(1, txManager1.begun);
assertEquals(1, txManager1.inflight);
assertEquals(0, txManager1.commits);
diff --git a/spring-test/src/test/java/org/springframework/test/context/junit4/spr9645/LookUpTxMgrByTypeAndQualifierAtClassLevelTests.java b/spring-test/src/test/java/org/springframework/test/context/junit4/spr9645/LookUpTxMgrByTypeAndQualifierAtClassLevelTests.java
index cd78baea45..bbc0951e4f 100644
--- a/spring-test/src/test/java/org/springframework/test/context/junit4/spr9645/LookUpTxMgrByTypeAndQualifierAtClassLevelTests.java
+++ b/spring-test/src/test/java/org/springframework/test/context/junit4/spr9645/LookUpTxMgrByTypeAndQualifierAtClassLevelTests.java
@@ -66,7 +66,7 @@ public class LookUpTxMgrByTypeAndQualifierAtClassLevelTests {
}
@Test
- public void lookUpByTypeAndQualifier() {
+ public void transactionalTest() {
assertEquals(1, txManager1.begun);
assertEquals(1, txManager1.inflight);
assertEquals(0, txManager1.commits);
diff --git a/spring-test/src/test/java/org/springframework/test/context/junit4/spr9645/LookUpTxMgrByTypeAndQualifierAtMethodLevelTests.java b/spring-test/src/test/java/org/springframework/test/context/junit4/spr9645/LookUpTxMgrByTypeAndQualifierAtMethodLevelTests.java
index 0a9335dbca..b9d6b4b6ae 100644
--- a/spring-test/src/test/java/org/springframework/test/context/junit4/spr9645/LookUpTxMgrByTypeAndQualifierAtMethodLevelTests.java
+++ b/spring-test/src/test/java/org/springframework/test/context/junit4/spr9645/LookUpTxMgrByTypeAndQualifierAtMethodLevelTests.java
@@ -66,7 +66,7 @@ public class LookUpTxMgrByTypeAndQualifierAtMethodLevelTests {
@Transactional("txManager1")
@Test
- public void lookUpByTypeAndQualifier() {
+ public void transactionalTest() {
assertEquals(1, txManager1.begun);
assertEquals(1, txManager1.inflight);
assertEquals(0, txManager1.commits);
diff --git a/spring-test/src/test/java/org/springframework/test/context/junit4/spr9645/LookUpTxMgrByTypeTests.java b/spring-test/src/test/java/org/springframework/test/context/junit4/spr9645/LookUpTxMgrByTypeTests.java
index ed48479805..b7a52aa961 100644
--- a/spring-test/src/test/java/org/springframework/test/context/junit4/spr9645/LookUpTxMgrByTypeTests.java
+++ b/spring-test/src/test/java/org/springframework/test/context/junit4/spr9645/LookUpTxMgrByTypeTests.java
@@ -59,7 +59,7 @@ public class LookUpTxMgrByTypeTests {
}
@Test
- public void lookUpByType() {
+ public void transactionalTest() {
assertEquals(1, txManager.begun);
assertEquals(1, txManager.inflight);
assertEquals(0, txManager.commits);
diff --git a/src/dist/changelog.txt b/src/dist/changelog.txt
index 4c8f1c6443..485b040f9f 100644
--- a/src/dist/changelog.txt
+++ b/src/dist/changelog.txt
@@ -29,6 +29,7 @@ Changes in version 3.2 M2 (2012-08-xx)
* support content negotiation options in MVC namespace and MVC Java config
* support named dispatchers in MockServletContext (SPR-9587)
* support single, unqualified tx manager in the TestContext framework (SPR-9645)
+* support TransactionManagementConfigurer in the TestContext framework (SPR-9604)
Changes in version 3.2 M1 (2012-05-28)
diff --git a/src/reference/docbook/testing.xml b/src/reference/docbook/testing.xml
index 0f8a4bf064..ed0f0499aa 100644
--- a/src/reference/docbook/testing.xml
+++ b/src/reference/docbook/testing.xml
@@ -630,9 +630,9 @@ public class CustomTestExecutionListenerTests {
Defines class-level metadata for configuring transactional
tests. Specifically, the bean name of the
- PlatformTransactionManager that is
- to be used to drive transactions can be explicitly specified if
- there are multiple beans of type
+ PlatformTransactionManager that
+ should be used to drive transactions can be explicitly specified
+ if there are multiple beans of type
PlatformTransactionManager in the
test's ApplicationContext and the
bean name of the desired
@@ -657,9 +657,12 @@ public class CustomConfiguredTransactionalTests {
configuration, you can avoid using
@TransactionConfiguration
altogether. In other words, if you have only one transaction
- manger (or your transaction manager bean is named
- "transactionManager") and if you want transactions to roll back
- automatically, there is no need to annotate your test class with
+ manger — or if you have multiple transaction mangers but the
+ transaction manager for tests is named "transactionManager" or
+ specified via a
+ TransactionManagementConfigurer —
+ and if you want transactions to roll back automatically, then
+ there is no need to annotate your test class with
@TransactionConfiguration.