diff --git a/spring-tx/src/main/java/org/springframework/transaction/annotation/Transactional.java b/spring-tx/src/main/java/org/springframework/transaction/annotation/Transactional.java index d399e8b04e..d1a52caf50 100644 --- a/spring-tx/src/main/java/org/springframework/transaction/annotation/Transactional.java +++ b/spring-tx/src/main/java/org/springframework/transaction/annotation/Transactional.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2021 the original author or authors. + * Copyright 2002-2022 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. @@ -37,17 +37,57 @@ import org.springframework.transaction.TransactionDefinition; * Transaction Management * section of the reference manual. * - *
This annotation type is generally directly comparable to Spring's + *
This annotation is generally directly comparable to Spring's * {@link org.springframework.transaction.interceptor.RuleBasedTransactionAttribute} * class, and in fact {@link AnnotationTransactionAttributeSource} will directly - * convert the data to the latter class, so that Spring's transaction support code - * does not have to know about annotations. If no custom rollback rules apply, - * the transaction will roll back on {@link RuntimeException} and {@link Error} - * but not on checked exceptions. + * convert this annotation's attributes to properties in {@code RuleBasedTransactionAttribute}, + * so that Spring's transaction support code does not have to know about annotations. * - *
For specific information about the semantics of this annotation's attributes, - * consult the {@link org.springframework.transaction.TransactionDefinition} and - * {@link org.springframework.transaction.interceptor.TransactionAttribute} javadocs. + *
If no custom rollback rules are configured in this annotation, the transaction + * will roll back on {@link RuntimeException} and {@link Error} but not on checked + * exceptions. + * + *
Rollback rules determine if a transaction should be rolled back when a given + * exception is thrown, and the rules are based on patterns. A pattern can be a + * fully qualified class name or a substring of a fully qualified class name for + * an exception type (which must be a subclass of {@code Throwable}), with no + * wildcard support at present. For example, a value of + * {@code "jakarta.servlet.ServletException"} or {@code "ServletException"} will + * match {@code jakarta.servlet.ServletException} and its subclasses. + * + *
Rollback rules may be configured via {@link #rollbackFor}/{@link #noRollbackFor} + * and {@link #rollbackForClassName}/{@link #noRollbackForClassName}, which allow + * patterns to be specified as {@link Class} references or {@linkplain String + * strings}, respectively. When an exception type is specified as a class reference + * its fully qualified name will be used as the pattern. Consequently, + * {@code @Transactional(rollbackFor = example.CustomException.class)} is equivalent + * to {@code @Transactional(rollbackForClassName = "example.CustomException")}. + * + *
WARNING: You must carefully consider how specific the pattern + * is and whether to include package information (which isn't mandatory). For example, + * {@code "Exception"} will match nearly anything and will probably hide other + * rules. {@code "java.lang.Exception"} would be correct if {@code "Exception"} + * were meant to define a rule for all checked exceptions. With more unique + * exception names such as {@code "BaseBusinessException"} there is likely no + * need to use the fully qualified class name for the exception pattern. Furthermore, + * rollback rules may result in unintentional matches for similarly named exceptions + * and nested classes. This is due to the fact that a thrown exception is considered + * to be a match for a given rollback rule if the name of thrown exception contains + * the exception pattern configured for the rollback rule. For example, given a + * rule configured to match on {@code com.example.CustomException}, that rule + * would match against an exception named + * {@code com.example.CustomExceptionV2} (an exception in the same package as + * {@code CustomException} but with an additional suffix) or an exception named + * {@code com.example.CustomException$AnotherException} + * (an exception declared as a nested class in {@code CustomException}). + * + *
For specific information about the semantics of other attributes in this + * annotation, consult the {@link org.springframework.transaction.TransactionDefinition} + * and {@link org.springframework.transaction.interceptor.TransactionAttribute} javadocs. + * + *
This annotation commonly works with thread-bound transactions managed by a * {@link org.springframework.transaction.PlatformTransactionManager}, exposing a @@ -167,37 +207,33 @@ public @interface Transactional { boolean readOnly() default false; /** - * Defines zero (0) or more exception {@link Class classes}, which must be + * Defines zero (0) or more exception {@linkplain Class classes}, which must be * subclasses of {@link Throwable}, indicating which exception types must cause * a transaction rollback. - *
By default, a transaction will be rolling back on {@link RuntimeException} + *
By default, a transaction will be rolled back on {@link RuntimeException} * and {@link Error} but not on checked exceptions (business exceptions). See * {@link org.springframework.transaction.interceptor.DefaultTransactionAttribute#rollbackOn(Throwable)} * for a detailed explanation. *
This is the preferred way to construct a rollback rule (in contrast to - * {@link #rollbackForClassName}), matching the exception class and its subclasses. - *
Similar to {@link org.springframework.transaction.interceptor.RollbackRuleAttribute#RollbackRuleAttribute(Class clazz)}. + * {@link #rollbackForClassName}), matching the exception type, its subclasses, + * and its nested classes. See the {@linkplain Transactional class-level javadocs} + * for further details on rollback rule semantics and warnings regarding possible + * unintentional matches. * @see #rollbackForClassName + * @see org.springframework.transaction.interceptor.RollbackRuleAttribute#RollbackRuleAttribute(Class) * @see org.springframework.transaction.interceptor.DefaultTransactionAttribute#rollbackOn(Throwable) */ Class extends Throwable>[] rollbackFor() default {}; /** - * Defines zero (0) or more exception names (for exceptions which must be a + * Defines zero (0) or more exception name patterns (for exceptions which must be a * subclass of {@link Throwable}), indicating which exception types must cause * a transaction rollback. - *
This can be a substring of a fully qualified class name, with no wildcard - * support at present. For example, a value of {@code "ServletException"} would - * match {@code jakarta.servlet.ServletException} and its subclasses. - *
NB: Consider carefully how specific the pattern is and whether - * to include package information (which isn't mandatory). For example, - * {@code "Exception"} will match nearly anything and will probably hide other - * rules. {@code "java.lang.Exception"} would be correct if {@code "Exception"} - * were meant to define a rule for all checked exceptions. With more unusual - * {@link Exception} names such as {@code "BaseBusinessException"} there is no - * need to use a FQN. - *
Similar to {@link org.springframework.transaction.interceptor.RollbackRuleAttribute#RollbackRuleAttribute(String exceptionName)}. + *
See the {@linkplain Transactional class-level javadocs} for further details + * on rollback rule semantics, patterns, and warnings regarding possible + * unintentional matches. * @see #rollbackFor + * @see org.springframework.transaction.interceptor.RollbackRuleAttribute#RollbackRuleAttribute(String) * @see org.springframework.transaction.interceptor.DefaultTransactionAttribute#rollbackOn(Throwable) */ String[] rollbackForClassName() default {}; @@ -206,23 +242,26 @@ public @interface Transactional { * Defines zero (0) or more exception {@link Class Classes}, which must be * subclasses of {@link Throwable}, indicating which exception types must * not cause a transaction rollback. - *
This is the preferred way to construct a rollback rule (in contrast - * to {@link #noRollbackForClassName}), matching the exception class and - * its subclasses. - *
Similar to {@link org.springframework.transaction.interceptor.NoRollbackRuleAttribute#NoRollbackRuleAttribute(Class clazz)}. + *
This is the preferred way to construct a rollback rule (in contrast to + * {@link #noRollbackForClassName}), matching the exception type, its subclasses, + * and its nested classes. See the {@linkplain Transactional class-level javadocs} + * for further details on rollback rule semantics and warnings regarding possible + * unintentional matches. * @see #noRollbackForClassName + * @see org.springframework.transaction.interceptor.NoRollbackRuleAttribute#NoRollbackRuleAttribute(Class) * @see org.springframework.transaction.interceptor.DefaultTransactionAttribute#rollbackOn(Throwable) */ Class extends Throwable>[] noRollbackFor() default {}; /** - * Defines zero (0) or more exception names (for exceptions which must be a + * Defines zero (0) or more exception name patterns (for exceptions which must be a * subclass of {@link Throwable}) indicating which exception types must not * cause a transaction rollback. - *
See the description of {@link #rollbackForClassName} for further - * information on how the specified names are treated. - *
Similar to {@link org.springframework.transaction.interceptor.NoRollbackRuleAttribute#NoRollbackRuleAttribute(String exceptionName)}. + *
See the {@linkplain Transactional class-level javadocs} for further details + * on rollback rule semantics, patterns, and warnings regarding possible + * unintentional matches. * @see #noRollbackFor + * @see org.springframework.transaction.interceptor.NoRollbackRuleAttribute#NoRollbackRuleAttribute(String) * @see org.springframework.transaction.interceptor.DefaultTransactionAttribute#rollbackOn(Throwable) */ String[] noRollbackForClassName() default {}; diff --git a/spring-tx/src/main/java/org/springframework/transaction/interceptor/NoRollbackRuleAttribute.java b/spring-tx/src/main/java/org/springframework/transaction/interceptor/NoRollbackRuleAttribute.java index a92e14b9ff..2282274a94 100644 --- a/spring-tx/src/main/java/org/springframework/transaction/interceptor/NoRollbackRuleAttribute.java +++ b/spring-tx/src/main/java/org/springframework/transaction/interceptor/NoRollbackRuleAttribute.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2012 the original author or authors. + * Copyright 2002-2022 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,7 @@ package org.springframework.transaction.interceptor; * to the {@code RollbackRuleAttribute} superclass. * * @author Rod Johnson + * @author Sam Brannen * @since 09.04.2003 */ @SuppressWarnings("serial") @@ -28,22 +29,28 @@ public class NoRollbackRuleAttribute extends RollbackRuleAttribute { /** * Create a new instance of the {@code NoRollbackRuleAttribute} class - * for the supplied {@link Throwable} class. - * @param clazz the {@code Throwable} class + * for the given {@code exceptionType}. + * @param exceptionType exception type; must be {@link Throwable} or a subclass + * of {@code Throwable} + * @throws IllegalArgumentException if the supplied {@code exceptionType} is + * not a {@code Throwable} type or is {@code null} * @see RollbackRuleAttribute#RollbackRuleAttribute(Class) */ - public NoRollbackRuleAttribute(Class> clazz) { - super(clazz); + public NoRollbackRuleAttribute(Class> exceptionType) { + super(exceptionType); } /** * Create a new instance of the {@code NoRollbackRuleAttribute} class - * for the supplied {@code exceptionName}. - * @param exceptionName the exception name pattern + * for the supplied {@code exceptionPattern}. + * @param exceptionPattern the exception name pattern; can also be a fully + * package-qualified class name + * @throws IllegalArgumentException if the supplied {@code exceptionPattern} + * is {@code null} or empty * @see RollbackRuleAttribute#RollbackRuleAttribute(String) */ - public NoRollbackRuleAttribute(String exceptionName) { - super(exceptionName); + public NoRollbackRuleAttribute(String exceptionPattern) { + super(exceptionPattern); } @Override diff --git a/spring-tx/src/main/java/org/springframework/transaction/interceptor/RollbackRuleAttribute.java b/spring-tx/src/main/java/org/springframework/transaction/interceptor/RollbackRuleAttribute.java index f9defeecd4..fff46ec2a1 100644 --- a/spring-tx/src/main/java/org/springframework/transaction/interceptor/RollbackRuleAttribute.java +++ b/spring-tx/src/main/java/org/springframework/transaction/interceptor/RollbackRuleAttribute.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2021 the original author or authors. + * Copyright 2002-2022 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,13 +22,29 @@ import org.springframework.lang.Nullable; import org.springframework.util.Assert; /** - * Rule determining whether or not a given exception (and any subclasses) - * should cause a rollback. + * Rule determining whether or not a given exception should cause a rollback. * *
Multiple such rules can be applied to determine whether a transaction * should commit or rollback after an exception has been thrown. * + *
Each rule is based on an exception pattern which can be a fully qualified + * class name or a substring of a fully qualified class name for an exception + * type (which must be a subclass of {@code Throwable}), with no wildcard support + * at present. For example, a value of {@code "jakarta.servlet.ServletException"} + * or {@code "ServletException"} would match {@code jakarta.servlet.ServletException} + * and its subclasses. + * + *
An exception pattern can be specified as a {@link Class} reference or a + * {@link String} in {@link #RollbackRuleAttribute(Class)} and + * {@link #RollbackRuleAttribute(String)}, respectively. When an exception type + * is specified as a class reference its fully qualified name will be used as the + * pattern. See the javadocs for + * {@link org.springframework.transaction.annotation.Transactional @Transactional} + * for further details on rollback rule semantics, patterns, and warnings regarding + * possible unintentional matches. + * * @author Rod Johnson + * @author Sam Brannen * @since 09.04.2003 * @see NoRollbackRuleAttribute */ @@ -36,7 +52,7 @@ import org.springframework.util.Assert; public class RollbackRuleAttribute implements Serializable{ /** - * The {@link RollbackRuleAttribute rollback rule} for + * The {@linkplain RollbackRuleAttribute rollback rule} for * {@link RuntimeException RuntimeExceptions}. */ public static final RollbackRuleAttribute ROLLBACK_ON_RUNTIME_EXCEPTIONS = @@ -48,79 +64,90 @@ public class RollbackRuleAttribute implements Serializable{ * This way does multiple string comparisons, but how often do we decide * whether to roll back a transaction following an exception? */ - private final String exceptionName; + private final String exceptionPattern; /** - * Create a new instance of the {@code RollbackRuleAttribute} class. + * Create a new instance of the {@code RollbackRuleAttribute} class + * for the given {@code exceptionType}. *
This is the preferred way to construct a rollback rule that matches - * the supplied {@link Exception} class, its subclasses, and its nested classes. - * @param clazz throwable class; must be {@link Throwable} or a subclass + * the supplied exception type, its subclasses, and its nested classes. + *
See the javadocs for + * {@link org.springframework.transaction.annotation.Transactional @Transactional} + * for further details on rollback rule semantics, patterns, and warnings regarding + * possible unintentional matches. + * @param exceptionType exception type; must be {@link Throwable} or a subclass * of {@code Throwable} - * @throws IllegalArgumentException if the supplied {@code clazz} is + * @throws IllegalArgumentException if the supplied {@code exceptionType} is * not a {@code Throwable} type or is {@code null} */ - public RollbackRuleAttribute(Class> clazz) { - Assert.notNull(clazz, "'clazz' cannot be null"); - if (!Throwable.class.isAssignableFrom(clazz)) { + public RollbackRuleAttribute(Class> exceptionType) { + Assert.notNull(exceptionType, "'exceptionType' cannot be null"); + if (!Throwable.class.isAssignableFrom(exceptionType)) { throw new IllegalArgumentException( - "Cannot construct rollback rule from [" + clazz.getName() + "]: it's not a Throwable"); + "Cannot construct rollback rule from [" + exceptionType.getName() + "]: it's not a Throwable"); } - this.exceptionName = clazz.getName(); + this.exceptionPattern = exceptionType.getName(); } /** * Create a new instance of the {@code RollbackRuleAttribute} class - * for the given {@code exceptionName}. - *
This can be a substring, with no wildcard support at present. A value - * of "ServletException" would match - * {@code jakarta.servlet.ServletException} and subclasses, for example. - *
NB: Consider carefully how specific the pattern is, and - * whether to include package information (which is not mandatory). For - * example, "Exception" will match nearly anything, and will probably hide - * other rules. "java.lang.Exception" would be correct if "Exception" was - * meant to define a rule for all checked exceptions. With more unusual - * exception names such as "BaseBusinessException" there's no need to use a - * fully package-qualified name. - * @param exceptionName the exception name pattern; can also be a fully + * for the given {@code exceptionPattern}. + *
See the javadocs for + * {@link org.springframework.transaction.annotation.Transactional @Transactional} + * for further details on rollback rule semantics, patterns, and warnings regarding + * possible unintentional matches. + * @param exceptionPattern the exception name pattern; can also be a fully * package-qualified class name - * @throws IllegalArgumentException if the supplied - * {@code exceptionName} is {@code null} or empty + * @throws IllegalArgumentException if the supplied {@code exceptionPattern} + * is {@code null} or empty */ - public RollbackRuleAttribute(String exceptionName) { - Assert.hasText(exceptionName, "'exceptionName' cannot be null or empty"); - this.exceptionName = exceptionName; + public RollbackRuleAttribute(String exceptionPattern) { + Assert.hasText(exceptionPattern, "'exceptionPattern' cannot be null or empty"); + this.exceptionPattern = exceptionPattern; } /** - * Return the pattern for the exception name. + * Get the configured exception name pattern that this rule uses for matching. + * @see #getDepth(Throwable) */ public String getExceptionName() { - return this.exceptionName; + return this.exceptionPattern; } /** - * Return the depth of the superclass matching. - *
{@code 0} means {@code ex} matches exactly. Returns - * {@code -1} if there is no match. Otherwise, returns depth with the - * lowest depth winning. + * Return the depth of the superclass matching, with the following semantics. + *
When comparing roll back rules that match against a given exception, a rule + * with a lower matching depth wins. For example, a direct match ({@code depth == 0}) + * wins over a match in the superclass hierarchy ({@code depth > 0}). + *
A match against a nested exception type or similarly named exception type
+ * will return a depth signifying a match at the corresponding level in the
+ * class hierarchy as if there had been a direct match.
*/
- public int getDepth(Throwable ex) {
- return getDepth(ex.getClass(), 0);
+ public int getDepth(Throwable exception) {
+ return getDepth(exception.getClass(), 0);
}
- private int getDepth(Class> exceptionClass, int depth) {
- if (exceptionClass.getName().contains(this.exceptionName)) {
+ private int getDepth(Class> exceptionType, int depth) {
+ if (exceptionType.getName().contains(this.exceptionPattern)) {
// Found it!
return depth;
}
// If we've gone as far as we can go and haven't found it...
- if (exceptionClass == Throwable.class) {
+ if (exceptionType == Throwable.class) {
return -1;
}
- return getDepth(exceptionClass.getSuperclass(), depth + 1);
+ return getDepth(exceptionType.getSuperclass(), depth + 1);
}
@@ -132,17 +159,17 @@ public class RollbackRuleAttribute implements Serializable{
if (!(other instanceof RollbackRuleAttribute rhs)) {
return false;
}
- return this.exceptionName.equals(rhs.exceptionName);
+ return this.exceptionPattern.equals(rhs.exceptionPattern);
}
@Override
public int hashCode() {
- return this.exceptionName.hashCode();
+ return this.exceptionPattern.hashCode();
}
@Override
public String toString() {
- return "RollbackRuleAttribute with pattern [" + this.exceptionName + "]";
+ return "RollbackRuleAttribute with pattern [" + this.exceptionPattern + "]";
}
}
diff --git a/spring-tx/src/test/java/org/springframework/transaction/interceptor/MyRuntimeException.java b/spring-tx/src/test/java/org/springframework/transaction/interceptor/MyRuntimeException.java
index 80affe6bc2..5b512e1eb8 100644
--- a/spring-tx/src/test/java/org/springframework/transaction/interceptor/MyRuntimeException.java
+++ b/spring-tx/src/test/java/org/springframework/transaction/interceptor/MyRuntimeException.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2012 the original author or authors.
+ * Copyright 2002-2022 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.
@@ -25,7 +25,13 @@ import org.springframework.core.NestedRuntimeException;
*/
@SuppressWarnings("serial")
class MyRuntimeException extends NestedRuntimeException {
+
+ public MyRuntimeException() {
+ super("");
+ }
+
public MyRuntimeException(String msg) {
super(msg);
}
+
}
diff --git a/spring-tx/src/test/java/org/springframework/transaction/interceptor/RollbackRuleAttributeTests.java b/spring-tx/src/test/java/org/springframework/transaction/interceptor/RollbackRuleAttributeTests.java
index fd05ff6755..f210659af3 100644
--- a/spring-tx/src/test/java/org/springframework/transaction/interceptor/RollbackRuleAttributeTests.java
+++ b/spring-tx/src/test/java/org/springframework/transaction/interceptor/RollbackRuleAttributeTests.java
@@ -18,6 +18,7 @@ package org.springframework.transaction.interceptor;
import java.io.IOException;
+import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
import org.springframework.beans.FatalBeanException;
@@ -36,65 +37,105 @@ import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException
*/
class RollbackRuleAttributeTests {
- @Test
- void constructorArgumentMustBeThrowableClassWithNonThrowableType() {
- assertThatIllegalArgumentException().isThrownBy(() -> new RollbackRuleAttribute(Object.class));
+ @Nested
+ class ExceptionPatternTests {
+
+ @Test
+ void constructorPreconditions() {
+ assertThatIllegalArgumentException().isThrownBy(() -> new RollbackRuleAttribute((String) null));
+ }
+
+ @Test
+ void notFound() {
+ RollbackRuleAttribute rr = new RollbackRuleAttribute(IOException.class.getName());
+ assertThat(rr.getDepth(new MyRuntimeException())).isEqualTo(-1);
+ }
+
+ @Test
+ void alwaysFoundForThrowable() {
+ RollbackRuleAttribute rr = new RollbackRuleAttribute(Throwable.class.getName());
+ assertThat(rr.getDepth(new MyRuntimeException())).isGreaterThan(0);
+ assertThat(rr.getDepth(new IOException())).isGreaterThan(0);
+ assertThat(rr.getDepth(new FatalBeanException(null, null))).isGreaterThan(0);
+ assertThat(rr.getDepth(new RuntimeException())).isGreaterThan(0);
+ }
+
+ @Test
+ void foundImmediatelyWhenDirectMatch() {
+ RollbackRuleAttribute rr = new RollbackRuleAttribute(Exception.class.getName());
+ assertThat(rr.getDepth(new Exception())).isEqualTo(0);
+ }
+
+ @Test
+ void foundImmediatelyWhenExceptionThrownIsNestedTypeOfRegisteredException() {
+ RollbackRuleAttribute rr = new RollbackRuleAttribute(EnclosingException.class.getName());
+ assertThat(rr.getDepth(new EnclosingException.NestedException())).isEqualTo(0);
+ }
+
+ @Test
+ void foundImmediatelyWhenNameOfExceptionThrownStartsWithNameOfRegisteredException() {
+ RollbackRuleAttribute rr = new RollbackRuleAttribute(MyException.class.getName());
+ assertThat(rr.getDepth(new MyException2())).isEqualTo(0);
+ }
+
+ @Test
+ void foundInSuperclassHierarchy() {
+ RollbackRuleAttribute rr = new RollbackRuleAttribute(Exception.class.getName());
+ // Exception -> RuntimeException -> NestedRuntimeException -> MyRuntimeException
+ assertThat(rr.getDepth(new MyRuntimeException())).isEqualTo(3);
+ }
+
}
- @Test
- void constructorArgumentMustBeThrowableClassWithNullThrowableType() {
- assertThatIllegalArgumentException().isThrownBy(() -> new RollbackRuleAttribute((Class>) null));
- }
+ @Nested
+ class ExceptionTypeTests {
- @Test
- void constructorArgumentMustBeStringWithNull() {
- assertThatIllegalArgumentException().isThrownBy(() -> new RollbackRuleAttribute((String) null));
- }
+ @Test
+ void constructorPreconditions() {
+ assertThatIllegalArgumentException().isThrownBy(() -> new RollbackRuleAttribute(Object.class));
+ assertThatIllegalArgumentException().isThrownBy(() -> new RollbackRuleAttribute((Class>) null));
+ }
- @Test
- void notFound() {
- RollbackRuleAttribute rr = new RollbackRuleAttribute(IOException.class);
- assertThat(rr.getDepth(new MyRuntimeException(""))).isEqualTo(-1);
- }
+ @Test
+ void notFound() {
+ RollbackRuleAttribute rr = new RollbackRuleAttribute(IOException.class);
+ assertThat(rr.getDepth(new MyRuntimeException())).isEqualTo(-1);
+ }
- @Test
- void foundImmediatelyWithString() {
- RollbackRuleAttribute rr = new RollbackRuleAttribute(Exception.class.getName());
- assertThat(rr.getDepth(new Exception())).isEqualTo(0);
- }
+ @Test
+ void alwaysFoundForThrowable() {
+ RollbackRuleAttribute rr = new RollbackRuleAttribute(Throwable.class);
+ assertThat(rr.getDepth(new MyRuntimeException())).isGreaterThan(0);
+ assertThat(rr.getDepth(new IOException())).isGreaterThan(0);
+ assertThat(rr.getDepth(new FatalBeanException(null, null))).isGreaterThan(0);
+ assertThat(rr.getDepth(new RuntimeException())).isGreaterThan(0);
+ }
- @Test
- void foundImmediatelyWithClass() {
- RollbackRuleAttribute rr = new RollbackRuleAttribute(Exception.class);
- assertThat(rr.getDepth(new Exception())).isEqualTo(0);
- }
+ @Test
+ void foundImmediatelyWhenDirectMatch() {
+ RollbackRuleAttribute rr = new RollbackRuleAttribute(Exception.class);
+ assertThat(rr.getDepth(new Exception())).isEqualTo(0);
+ }
- @Test
- void foundInSuperclassHierarchy() {
- RollbackRuleAttribute rr = new RollbackRuleAttribute(Exception.class);
- // Exception -> RuntimeException -> NestedRuntimeException -> MyRuntimeException
- assertThat(rr.getDepth(new MyRuntimeException(""))).isEqualTo(3);
- }
+ @Test
+ void foundImmediatelyWhenExceptionThrownIsNestedTypeOfRegisteredException() {
+ RollbackRuleAttribute rr = new RollbackRuleAttribute(EnclosingException.class);
+ assertThat(rr.getDepth(new EnclosingException.NestedException())).isEqualTo(0);
+ }
- @Test
- void alwaysFoundForThrowable() {
- RollbackRuleAttribute rr = new RollbackRuleAttribute(Throwable.class);
- assertThat(rr.getDepth(new MyRuntimeException(""))).isGreaterThan(0);
- assertThat(rr.getDepth(new IOException())).isGreaterThan(0);
- assertThat(rr.getDepth(new FatalBeanException(null, null))).isGreaterThan(0);
- assertThat(rr.getDepth(new RuntimeException())).isGreaterThan(0);
- }
+ @Test
+ void foundImmediatelyWhenNameOfExceptionThrownStartsWithNameOfRegisteredException() {
+ RollbackRuleAttribute rr = new RollbackRuleAttribute(MyException.class);
+ assertThat(rr.getDepth(new MyException2())).isEqualTo(0);
+ }
- @Test
- void foundNestedExceptionInEnclosingException() {
- RollbackRuleAttribute rr = new RollbackRuleAttribute(EnclosingException.class);
- assertThat(rr.getDepth(new EnclosingException.NestedException())).isEqualTo(0);
- }
+ @Test
+ void foundInSuperclassHierarchy() {
+ RollbackRuleAttribute rr = new RollbackRuleAttribute(Exception.class);
+ // Exception -> RuntimeException -> NestedRuntimeException -> MyRuntimeException
+ assertThat(rr.getDepth(new MyRuntimeException())).isEqualTo(3);
+ }
- @Test
- void foundWhenNameOfExceptionThrownStartsWithTheNameOfTheRegisteredExceptionType() {
- RollbackRuleAttribute rr = new RollbackRuleAttribute(MyException.class);
- assertThat(rr.getDepth(new MyException2())).isEqualTo(0);
}
diff --git a/spring-tx/src/test/java/org/springframework/transaction/interceptor/RuleBasedTransactionAttributeTests.java b/spring-tx/src/test/java/org/springframework/transaction/interceptor/RuleBasedTransactionAttributeTests.java
index 8aa9815e7c..3f4cffe2b8 100644
--- a/spring-tx/src/test/java/org/springframework/transaction/interceptor/RuleBasedTransactionAttributeTests.java
+++ b/spring-tx/src/test/java/org/springframework/transaction/interceptor/RuleBasedTransactionAttributeTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2020 the original author or authors.
+ * Copyright 2002-2022 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.
@@ -35,13 +35,13 @@ import static org.assertj.core.api.Assertions.assertThat;
* @author Chris Beams
* @since 09.04.2003
*/
-public class RuleBasedTransactionAttributeTests {
+class RuleBasedTransactionAttributeTests {
@Test
- public void testDefaultRule() {
+ void defaultRule() {
RuleBasedTransactionAttribute rta = new RuleBasedTransactionAttribute();
assertThat(rta.rollbackOn(new RuntimeException())).isTrue();
- assertThat(rta.rollbackOn(new MyRuntimeException(""))).isTrue();
+ assertThat(rta.rollbackOn(new MyRuntimeException())).isTrue();
assertThat(rta.rollbackOn(new Exception())).isFalse();
assertThat(rta.rollbackOn(new IOException())).isFalse();
}
@@ -50,20 +50,20 @@ public class RuleBasedTransactionAttributeTests {
* Test one checked exception that should roll back.
*/
@Test
- public void testRuleForRollbackOnChecked() {
+ void ruleForRollbackOnChecked() {
List