diff --git a/spring-test/src/main/java/org/springframework/test/context/transaction/AfterTransaction.java b/spring-test/src/main/java/org/springframework/test/context/transaction/AfterTransaction.java
index aeaac1355bf..a7f6653e886 100644
--- a/spring-test/src/main/java/org/springframework/test/context/transaction/AfterTransaction.java
+++ b/spring-test/src/main/java/org/springframework/test/context/transaction/AfterTransaction.java
@@ -23,12 +23,16 @@ import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
- *
Test annotation to indicate that the annotated {@code void} method
+ *
Test annotation which indicates that the annotated {@code void} method
* should be executed after a transaction is ended for a test method
- * configured to run within a transaction via the {@code @Transactional} annotation.
+ * configured to run within a transaction via Spring's {@code @Transactional}
+ * annotation.
*
- *
The {@code @AfterTransaction} methods of superclasses will be executed
- * after those of the current class.
+ *
As of Spring Framework 4.3, {@code @AfterTransaction} may be declared on
+ * Java 8 based interface default methods.
+ *
+ *
{@code @AfterTransaction} methods declared in superclasses or as interface
+ * default methods will be executed after those of the current test class.
*
*
As of Spring Framework 4.0, this annotation may be used as a
* meta-annotation to create custom composed annotations.
diff --git a/spring-test/src/main/java/org/springframework/test/context/transaction/BeforeTransaction.java b/spring-test/src/main/java/org/springframework/test/context/transaction/BeforeTransaction.java
index 418a077bf4f..217c7d1768b 100644
--- a/spring-test/src/main/java/org/springframework/test/context/transaction/BeforeTransaction.java
+++ b/spring-test/src/main/java/org/springframework/test/context/transaction/BeforeTransaction.java
@@ -23,12 +23,16 @@ import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
- *
Test annotation to indicate that the annotated {@code void} method
+ *
Test annotation which indicates that the annotated {@code void} method
* should be executed before a transaction is started for a test method
- * configured to run within a transaction via the {@code @Transactional} annotation.
+ * configured to run within a transaction via Spring's {@code @Transactional}
+ * annotation.
*
- *
The {@code @BeforeTransaction} methods of superclasses will be executed
- * before those of the current class.
+ *
As of Spring Framework 4.3, {@code @BeforeTransaction} may be declared on
+ * Java 8 based interface default methods.
+ *
+ *
{@code @BeforeTransaction} methods declared in superclasses or as interface
+ * default methods will be executed before those of the current test class.
*
*
As of Spring Framework 4.0, this annotation may be used as a
* meta-annotation to create custom composed annotations.
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 d81f1ddaa49..adb3cfa144e 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
@@ -97,9 +97,10 @@ import org.springframework.util.StringUtils;
*
When executing transactional tests, it is sometimes useful to be able to
* execute certain set up or tear down code outside of a
* transaction. {@code TransactionalTestExecutionListener} provides such
- * support for methods annotated with
- * {@link BeforeTransaction @BeforeTransaction} or
- * {@link AfterTransaction @AfterTransaction}.
+ * support for methods annotated with {@link BeforeTransaction @BeforeTransaction}
+ * or {@link AfterTransaction @AfterTransaction}. As of Spring Framework 4.3,
+ * {@code @BeforeTransaction} and {@code @AfterTransaction} may also be declared
+ * on Java 8 based interface default methods.
*
*
Configuring a Transaction Manager
* {@code TransactionalTestExecutionListener} expects a
@@ -431,90 +432,23 @@ public class TransactionalTestExecutionListener extends AbstractTestExecutionLis
}
/**
- * Gets all superclasses of the supplied {@link Class class}, including the
- * class itself. The ordering of the returned list will begin with the
- * supplied class and continue up the class hierarchy, excluding {@link Object}.
- *
Note: This code has been borrowed from
- * {@link org.junit.internal.runners.TestClass#getSuperClasses(Class)} and
- * adapted.
- * @param clazz the class for which to retrieve the superclasses
- * @return all superclasses of the supplied class, excluding {@code Object}
- */
- private List> getSuperClasses(Class> clazz) {
- List> results = new ArrayList>();
- Class> current = clazz;
- while (current != null && Object.class != current) {
- results.add(current);
- current = current.getSuperclass();
- }
- return results;
- }
-
- /**
- * Gets all methods in the supplied {@link Class class} and its superclasses
+ * Get all methods in the supplied {@link Class class} and its superclasses
* which are annotated with the supplied {@code annotationType} but
* which are not shadowed by methods overridden in subclasses.
- * Note: This code has been borrowed from
- * {@link org.junit.internal.runners.TestClass#getAnnotatedMethods(Class)}
- * and adapted.
+ *
Default methods on interfaces are also detected.
* @param clazz the class for which to retrieve the annotated methods
* @param annotationType the annotation type for which to search
* @return all annotated methods in the supplied class and its superclasses
+ * as well as annotated interface default methods
*/
private List getAnnotatedMethods(Class> clazz, Class extends Annotation> annotationType) {
- List results = new ArrayList();
- for (Class> current : getSuperClasses(clazz)) {
- for (Method method : current.getDeclaredMethods()) {
- Annotation annotation = AnnotationUtils.getAnnotation(method, annotationType);
- if (annotation != null && !isShadowed(method, results)) {
- results.add(method);
- }
- }
- }
- return results;
- }
-
- /**
- * Determine if the supplied {@link Method method} is shadowed by
- * a method in the supplied {@link List list} of previous methods.
- * Note: This code has been borrowed from
- * {@link org.junit.internal.runners.TestClass#isShadowed(Method, List)}.
- * @param method the method to check for shadowing
- * @param previousMethods the list of methods which have previously been processed
- * @return {@code true} if the supplied method is shadowed by a
- * method in the {@code previousMethods} list
- */
- private boolean isShadowed(Method method, List previousMethods) {
- for (Method each : previousMethods) {
- if (isShadowed(method, each)) {
- return true;
- }
- }
- return false;
- }
-
- /**
- * Determine if the supplied {@linkplain Method current method} is
- * shadowed by a {@linkplain Method previous method}.
- * Note: This code has been borrowed from
- * {@link org.junit.internal.runners.TestClass#isShadowed(Method, Method)}.
- * @param current the current method
- * @param previous the previous method
- * @return {@code true} if the previous method shadows the current one
- */
- private boolean isShadowed(Method current, Method previous) {
- if (!previous.getName().equals(current.getName())) {
- return false;
- }
- if (previous.getParameterTypes().length != current.getParameterTypes().length) {
- return false;
- }
- for (int i = 0; i < previous.getParameterTypes().length; i++) {
- if (!previous.getParameterTypes()[i].equals(current.getParameterTypes()[i])) {
- return false;
+ List methods = new ArrayList(4);
+ for (Method method : ReflectionUtils.getUniqueDeclaredMethods(clazz)) {
+ if (AnnotationUtils.getAnnotation(method, annotationType) != null) {
+ methods.add(method);
}
}
- return true;
+ return methods;
}
/**
diff --git a/spring-test/src/test/java/org/springframework/test/context/transaction/TransactionalTestExecutionListenerTests.java b/spring-test/src/test/java/org/springframework/test/context/transaction/TransactionalTestExecutionListenerTests.java
index 31975c73fdb..0e4f7276f8a 100644
--- a/spring-test/src/test/java/org/springframework/test/context/transaction/TransactionalTestExecutionListenerTests.java
+++ b/spring-test/src/test/java/org/springframework/test/context/transaction/TransactionalTestExecutionListenerTests.java
@@ -20,7 +20,6 @@ import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import org.junit.After;
-import org.junit.Ignore;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
@@ -245,13 +244,11 @@ public class TransactionalTestExecutionListenerTests {
assertAfterTestMethod(AfterTransactionDeclaredViaMetaAnnotationTestCase.class);
}
- @Ignore("Disabled until @BeforeTransaction is supported on interface default methods")
@Test
public void beforeTestMethodWithBeforeTransactionDeclaredAsInterfaceDefaultMethod() throws Exception {
assertBeforeTestMethod(BeforeTransactionDeclaredAsInterfaceDefaultMethodTestCase.class);
}
- @Ignore("Disabled until @AfterTransaction is supported on interface default methods")
@Test
public void afterTestMethodWithAfterTransactionDeclaredAsInterfaceDefaultMethod() throws Exception {
assertAfterTestMethod(AfterTransactionDeclaredAsInterfaceDefaultMethodTestCase.class);
diff --git a/src/asciidoc/testing.adoc b/src/asciidoc/testing.adoc
index baa0c8a4ed7..1156eb715d4 100644
--- a/src/asciidoc/testing.adoc
+++ b/src/asciidoc/testing.adoc
@@ -854,9 +854,12 @@ method, potentially overriding class-level `@Rollback` or `@Commit` semantics.
+
-Indicates that the annotated `void` method should be executed __before__ a
-transaction is started for test methods configured to run within a transaction via the
-`@Transactional` annotation.
+Indicates that the annotated `void` method should be executed __before__ a transaction
+is started for test methods configured to run within a transaction via Spring's
+`@Transactional` annotation. As of Spring Framework 4.3, `@BeforeTransaction` methods
+are not required to be `public` and may be declared on Java 8 based interface default
+methods.
+
+
@@ -873,9 +876,11 @@ transaction is started for test methods configured to run within a transaction v
+
-Indicates that the annotated `void` method should be executed __after__ a
-transaction has ended for test methods configured to run within a transaction via the
-`@Transactional` annotation.
+Indicates that the annotated `void` method should be executed __after__ a transaction
+is ended for test methods configured to run within a transaction via Spring's
+`@Transactional` annotation. As of Spring Framework 4.3, `@AfterTransaction` methods
+are not required to be `public` and may be declared on Java 8 based interface default
+methods.
+
@@ -3210,12 +3215,12 @@ javadocs for `TestTransaction` for further details.
Occasionally you need to execute certain code before or after a transactional test method
but outside the transactional context -- for example, to verify the initial database state
prior to execution of your test or to verify expected transactional commit behavior after
-test execution (if the test was configured not to roll back the transaction).
+test execution (if the test was configured to commit the transaction).
`TransactionalTestExecutionListener` supports the `@BeforeTransaction` and
`@AfterTransaction` annotations exactly for such scenarios. Simply annotate any `void`
-method in your test class with one of these annotations, and the
-`TransactionalTestExecutionListener` ensures that your __before transaction method__ or
-__after transaction method__ is executed at the appropriate time.
+method in a test class or any `void` default method in a test interface with one of these
+annotations, and the `TransactionalTestExecutionListener` ensures that your __before
+transaction method__ or __after transaction method__ is executed at the appropriate time.
[TIP]
====
diff --git a/src/asciidoc/whats-new.adoc b/src/asciidoc/whats-new.adoc
index 03fa76f07dd..17b4d8f4f0e 100644
--- a/src/asciidoc/whats-new.adoc
+++ b/src/asciidoc/whats-new.adoc
@@ -694,8 +694,9 @@ Spring 4.3 also improves the caching abstraction as follows:
* New `SpringRunner` _alias_ for the `SpringJUnit4ClassRunner`.
* An empty declaration of `@ContextConfiguration` can now be completely omitted if default
XML files, Groovy scripts, or `@Configuration` classes are detected.
-* `@Transactional` test methods are no longer required to be `public` (in TestNG and JUnit 5).
-* `@BeforeTransaction` and `@AfterTransaction` methods are no longer required to be `public`.
+* `@Transactional` test methods are no longer required to be `public` (e.g., in TestNG and JUnit 5).
+* `@BeforeTransaction` and `@AfterTransaction` methods are no longer required to be `public`
+ and may now be declared on Java 8 based interface default methods.
* The `ApplicationContext` cache in the _Spring TestContext Framework_ is now bounded with a
default maximum size of 32 and a _least recently used_ eviction policy. The maximum size
can be configured by setting a JVM system property or Spring property called