diff --git a/spring-tx/src/test/java/org/springframework/transaction/annotation/AnnotationTransactionAttributeSourceTests.java b/spring-tx/src/test/java/org/springframework/transaction/annotation/AnnotationTransactionAttributeSourceTests.java index d24ebd9b380..fa627266c7c 100644 --- a/spring-tx/src/test/java/org/springframework/transaction/annotation/AnnotationTransactionAttributeSourceTests.java +++ b/spring-tx/src/test/java/org/springframework/transaction/annotation/AnnotationTransactionAttributeSourceTests.java @@ -21,10 +21,13 @@ import java.io.Serializable; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.reflect.Method; +import java.util.Arrays; +import java.util.function.Consumer; import groovy.lang.GroovyObject; import groovy.lang.MetaClass; import jakarta.ejb.TransactionAttributeType; +import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; import org.springframework.aop.framework.Advised; @@ -39,23 +42,28 @@ import org.springframework.transaction.interceptor.RuleBasedTransactionAttribute import org.springframework.transaction.interceptor.TransactionAttribute; import org.springframework.transaction.interceptor.TransactionInterceptor; import org.springframework.transaction.testfixture.CallCountingTransactionManager; +import org.springframework.util.ReflectionUtils; import static org.assertj.core.api.Assertions.assertThat; /** + * Tests for {@link AnnotationTransactionAttributeSource}. + * * @author Colin Sampaleanu * @author Juergen Hoeller * @author Sam Brannen * @author Mark Paluch + * @author Stephane Nicoll */ class AnnotationTransactionAttributeSourceTests { + private final AnnotationTransactionAttributeSource attributeSource = new AnnotationTransactionAttributeSource(); + @Test void serializable() throws Exception { TestBean1 tb = new TestBean1(); CallCountingTransactionManager ptm = new CallCountingTransactionManager(); - AnnotationTransactionAttributeSource tas = new AnnotationTransactionAttributeSource(); - TransactionInterceptor ti = new TransactionInterceptor((TransactionManager) ptm, tas); + TransactionInterceptor ti = new TransactionInterceptor((TransactionManager) ptm, this.attributeSource); ProxyFactory proxyFactory = new ProxyFactory(); proxyFactory.setInterfaces(ITestBean1.class); @@ -75,14 +83,12 @@ class AnnotationTransactionAttributeSourceTests { } @Test - void nullOrEmpty() throws Exception { - Method method = Empty.class.getMethod("getAge"); - - AnnotationTransactionAttributeSource atas = new AnnotationTransactionAttributeSource(); - assertThat(atas.getTransactionAttribute(method, null)).isNull(); + void nullOrEmpty() { + Method method = getMethod(Empty.class, "getAge"); + assertThat(this.attributeSource.getTransactionAttribute(method, null)).isNull(); // Try again in case of caching - assertThat(atas.getTransactionAttribute(method, null)).isNull(); + assertThat(this.attributeSource.getTransactionAttribute(method, null)).isNull(); } /** @@ -90,15 +96,9 @@ class AnnotationTransactionAttributeSourceTests { * but the attribute is defined on the target class. */ @Test - void transactionAttributeDeclaredOnClassMethod() throws Exception { - Method classMethod = ITestBean1.class.getMethod("getAge"); - - AnnotationTransactionAttributeSource atas = new AnnotationTransactionAttributeSource(); - TransactionAttribute actual = atas.getTransactionAttribute(classMethod, TestBean1.class); - - RuleBasedTransactionAttribute rbta = new RuleBasedTransactionAttribute(); - rbta.getRollbackRules().add(new RollbackRuleAttribute(Exception.class)); - assertThat(((RuleBasedTransactionAttribute) actual).getRollbackRules()).isEqualTo(rbta.getRollbackRules()); + void transactionAttributeDeclaredOnClassMethod() { + TransactionAttribute actual = getTransactionAttribute(TestBean1.class, ITestBean1.class, "getAge"); + assertThat(actual).satisfies(hasRollbackRules(new RollbackRuleAttribute(Exception.class))); } /** @@ -106,107 +106,76 @@ class AnnotationTransactionAttributeSourceTests { * but the attribute is defined on the target class. */ @Test - void transactionAttributeDeclaredOnCglibClassMethod() throws Exception { - Method classMethod = ITestBean1.class.getMethod("getAge"); + void transactionAttributeDeclaredOnCglibClassMethod() { TestBean1 tb = new TestBean1(); ProxyFactory pf = new ProxyFactory(tb); pf.setProxyTargetClass(true); Object proxy = pf.getProxy(); - AnnotationTransactionAttributeSource atas = new AnnotationTransactionAttributeSource(); - TransactionAttribute actual = atas.getTransactionAttribute(classMethod, proxy.getClass()); - - RuleBasedTransactionAttribute rbta = new RuleBasedTransactionAttribute(); - rbta.getRollbackRules().add(new RollbackRuleAttribute(Exception.class)); - assertThat(((RuleBasedTransactionAttribute) actual).getRollbackRules()).isEqualTo(rbta.getRollbackRules()); + TransactionAttribute actual = getTransactionAttribute(proxy.getClass(), ITestBean1.class, "getAge"); + assertThat(actual).satisfies(hasRollbackRules(new RollbackRuleAttribute(Exception.class))); } /** * Test case where attribute is on the interface method. */ @Test - void transactionAttributeDeclaredOnInterfaceMethodOnly() throws Exception { - Method interfaceMethod = ITestBean2.class.getMethod("getAge"); - - AnnotationTransactionAttributeSource atas = new AnnotationTransactionAttributeSource(); - TransactionAttribute actual = atas.getTransactionAttribute(interfaceMethod, TestBean2.class); - - RuleBasedTransactionAttribute rbta = new RuleBasedTransactionAttribute(); - assertThat(((RuleBasedTransactionAttribute) actual).getRollbackRules()).isEqualTo(rbta.getRollbackRules()); + void transactionAttributeDeclaredOnInterfaceMethodOnly() { + TransactionAttribute actual = getTransactionAttribute(TestBean2.class, ITestBean2.class, "getAge"); + assertThat(actual).satisfies(hasNoRollbackRule()); } /** * Test that when an attribute exists on both class and interface, class takes precedence. */ @Test - void transactionAttributeOnTargetClassMethodOverridesAttributeOnInterfaceMethod() throws Exception { - Method interfaceMethod = ITestBean3.class.getMethod("getAge"); - Method interfaceMethod2 = ITestBean3.class.getMethod("setAge", int.class); - Method interfaceMethod3 = ITestBean3.class.getMethod("getName"); - - AnnotationTransactionAttributeSource atas = new AnnotationTransactionAttributeSource(); - atas.setEmbeddedValueResolver(strVal -> ("${myTimeout}".equals(strVal) ? "5" : strVal)); + void transactionAttributeOnTargetClassMethodOverridesAttributeOnInterfaceMethod() { + this.attributeSource.setEmbeddedValueResolver(strVal -> ("${myTimeout}".equals(strVal) ? "5" : strVal)); - TransactionAttribute actual = atas.getTransactionAttribute(interfaceMethod, TestBean3.class); + TransactionAttribute actual = getTransactionAttribute(TestBean3.class, ITestBean3.class, "getAge"); assertThat(actual.getPropagationBehavior()).isEqualTo(TransactionAttribute.PROPAGATION_REQUIRES_NEW); assertThat(actual.getIsolationLevel()).isEqualTo(TransactionAttribute.ISOLATION_REPEATABLE_READ); assertThat(actual.getTimeout()).isEqualTo(5); assertThat(actual.isReadOnly()).isTrue(); + assertThat(actual).satisfies(hasRollbackRules(new RollbackRuleAttribute(Exception.class), + new NoRollbackRuleAttribute(IOException.class))); - TransactionAttribute actual2 = atas.getTransactionAttribute(interfaceMethod2, TestBean3.class); + TransactionAttribute actual2 = getTransactionAttribute(TestBean3.class, ITestBean3.class, "setAge", int.class); assertThat(actual2.getPropagationBehavior()).isEqualTo(TransactionAttribute.PROPAGATION_REQUIRES_NEW); assertThat(actual2.getIsolationLevel()).isEqualTo(TransactionAttribute.ISOLATION_REPEATABLE_READ); assertThat(actual2.getTimeout()).isEqualTo(5); assertThat(actual2.isReadOnly()).isTrue(); + assertThat(actual2).satisfies(hasRollbackRules(new RollbackRuleAttribute(Exception.class), + new NoRollbackRuleAttribute(IOException.class))); - RuleBasedTransactionAttribute rbta = new RuleBasedTransactionAttribute(); - rbta.getRollbackRules().add(new RollbackRuleAttribute(Exception.class)); - rbta.getRollbackRules().add(new NoRollbackRuleAttribute(IOException.class)); - assertThat(((RuleBasedTransactionAttribute) actual).getRollbackRules()).isEqualTo(rbta.getRollbackRules()); - - TransactionAttribute actual3 = atas.getTransactionAttribute(interfaceMethod3, TestBean3.class); + TransactionAttribute actual3 = getTransactionAttribute(TestBean3.class, ITestBean3.class, "getName"); assertThat(actual3.getPropagationBehavior()).isEqualTo(TransactionAttribute.PROPAGATION_REQUIRED); } @Test - void rollbackRulesAreApplied() throws Exception { - Method method = TestBean3.class.getMethod("getAge"); - - AnnotationTransactionAttributeSource atas = new AnnotationTransactionAttributeSource(); - TransactionAttribute actual = atas.getTransactionAttribute(method, TestBean3.class); - - RuleBasedTransactionAttribute rbta = new RuleBasedTransactionAttribute(); - rbta.getRollbackRules().add(new RollbackRuleAttribute("java.lang.Exception")); - rbta.getRollbackRules().add(new NoRollbackRuleAttribute(IOException.class)); + void rollbackRulesAreApplied() { + Method method = getMethod(TestBean3.class, "getAge"); - assertThat(((RuleBasedTransactionAttribute) actual).getRollbackRules()).isEqualTo(rbta.getRollbackRules()); + TransactionAttribute actual = getTransactionAttribute(TestBean3.class, method); + assertThat(actual).satisfies(hasRollbackRules(new RollbackRuleAttribute("java.lang.Exception"), + new NoRollbackRuleAttribute(IOException.class))); assertThat(actual.rollbackOn(new Exception())).isTrue(); assertThat(actual.rollbackOn(new IOException())).isFalse(); - actual = atas.getTransactionAttribute(method, method.getDeclaringClass()); - - rbta = new RuleBasedTransactionAttribute(); - rbta.getRollbackRules().add(new RollbackRuleAttribute("java.lang.Exception")); - rbta.getRollbackRules().add(new NoRollbackRuleAttribute(IOException.class)); - - assertThat(((RuleBasedTransactionAttribute) actual).getRollbackRules()).isEqualTo(rbta.getRollbackRules()); - assertThat(actual.rollbackOn(new Exception())).isTrue(); - assertThat(actual.rollbackOn(new IOException())).isFalse(); + TransactionAttribute actual2 = getTransactionAttribute(method.getDeclaringClass(), method); + assertThat(actual2).satisfies(hasRollbackRules(new RollbackRuleAttribute("java.lang.Exception"), + new NoRollbackRuleAttribute(IOException.class))); + assertThat(actual2.rollbackOn(new Exception())).isTrue(); + assertThat(actual2.rollbackOn(new IOException())).isFalse(); } @Test - void labelsAreApplied() throws Exception { - Method method = TestBean11.class.getMethod("getAge"); - - AnnotationTransactionAttributeSource atas = new AnnotationTransactionAttributeSource(); - TransactionAttribute actual = atas.getTransactionAttribute(method, TestBean11.class); - + void labelsAreApplied() { + TransactionAttribute actual = getTransactionAttribute(TestBean11.class, TestBean11.class, "getAge"); assertThat(actual.getLabels()).containsOnly("retryable", "long-running"); - method = TestBean11.class.getMethod("setAge", int.class); - actual = atas.getTransactionAttribute(method, method.getDeclaringClass()); - - assertThat(actual.getLabels()).containsOnly("short-running"); + TransactionAttribute actual2 = getTransactionAttribute(TestBean11.class, TestBean11.class, "setAge", int.class); + assertThat(actual2.getLabels()).containsOnly("short-running"); } /** @@ -214,200 +183,425 @@ class AnnotationTransactionAttributeSourceTests { * if not specified on method. */ @Test - void defaultsToClassTransactionAttribute() throws Exception { - Method method = TestBean4.class.getMethod("getAge"); - - AnnotationTransactionAttributeSource atas = new AnnotationTransactionAttributeSource(); - TransactionAttribute actual = atas.getTransactionAttribute(method, TestBean4.class); - - RuleBasedTransactionAttribute rbta = new RuleBasedTransactionAttribute(); - rbta.getRollbackRules().add(new RollbackRuleAttribute(Exception.class)); - rbta.getRollbackRules().add(new NoRollbackRuleAttribute(IOException.class)); - assertThat(((RuleBasedTransactionAttribute) actual).getRollbackRules()).isEqualTo(rbta.getRollbackRules()); + void defaultsToClassTransactionAttribute() { + TransactionAttribute actual = getTransactionAttribute(TestBean4.class, TestBean4.class, "getAge"); + assertThat(actual).satisfies(hasRollbackRules(new RollbackRuleAttribute(Exception.class), + new NoRollbackRuleAttribute(IOException.class))); } @Test - void customClassAttributeDetected() throws Exception { - Method method = TestBean5.class.getMethod("getAge"); - - AnnotationTransactionAttributeSource atas = new AnnotationTransactionAttributeSource(); - TransactionAttribute actual = atas.getTransactionAttribute(method, TestBean5.class); - - RuleBasedTransactionAttribute rbta = new RuleBasedTransactionAttribute(); - rbta.getRollbackRules().add(new RollbackRuleAttribute(Exception.class)); - rbta.getRollbackRules().add(new NoRollbackRuleAttribute(IOException.class)); - assertThat(((RuleBasedTransactionAttribute) actual).getRollbackRules()).isEqualTo(rbta.getRollbackRules()); + void customClassAttributeDetected() { + TransactionAttribute actual = getTransactionAttribute(TestBean5.class, "getAge"); + assertThat(actual).satisfies(hasRollbackRules(new RollbackRuleAttribute(Exception.class), + new NoRollbackRuleAttribute(IOException.class))); } @Test - void customMethodAttributeDetected() throws Exception { - Method method = TestBean6.class.getMethod("getAge"); - - AnnotationTransactionAttributeSource atas = new AnnotationTransactionAttributeSource(); - TransactionAttribute actual = atas.getTransactionAttribute(method, TestBean6.class); - - RuleBasedTransactionAttribute rbta = new RuleBasedTransactionAttribute(); - rbta.getRollbackRules().add(new RollbackRuleAttribute(Exception.class)); - rbta.getRollbackRules().add(new NoRollbackRuleAttribute(IOException.class)); - assertThat(((RuleBasedTransactionAttribute) actual).getRollbackRules()).isEqualTo(rbta.getRollbackRules()); + void customMethodAttributeDetected() { + TransactionAttribute actual = getTransactionAttribute(TestBean6.class, "getAge"); + assertThat(actual).satisfies(hasRollbackRules(new RollbackRuleAttribute(Exception.class), + new NoRollbackRuleAttribute(IOException.class))); } @Test - void customClassAttributeWithReadOnlyOverrideDetected() throws Exception { - Method method = TestBean7.class.getMethod("getAge"); - - AnnotationTransactionAttributeSource atas = new AnnotationTransactionAttributeSource(); - TransactionAttribute actual = atas.getTransactionAttribute(method, TestBean7.class); - - RuleBasedTransactionAttribute rbta = new RuleBasedTransactionAttribute(); - rbta.getRollbackRules().add(new RollbackRuleAttribute(Exception.class)); - rbta.getRollbackRules().add(new NoRollbackRuleAttribute(IOException.class)); - assertThat(((RuleBasedTransactionAttribute) actual).getRollbackRules()).isEqualTo(rbta.getRollbackRules()); - + void customClassAttributeWithReadOnlyOverrideDetected() { + TransactionAttribute actual = getTransactionAttribute(TestBean7.class, "getAge"); + assertThat(actual).satisfies(hasRollbackRules(new RollbackRuleAttribute(Exception.class), + new NoRollbackRuleAttribute(IOException.class))); assertThat(actual.isReadOnly()).isTrue(); } @Test - void customMethodAttributeWithReadOnlyOverrideDetected() throws Exception { - Method method = TestBean8.class.getMethod("getAge"); - - AnnotationTransactionAttributeSource atas = new AnnotationTransactionAttributeSource(); - TransactionAttribute actual = atas.getTransactionAttribute(method, TestBean8.class); - - RuleBasedTransactionAttribute rbta = new RuleBasedTransactionAttribute(); - rbta.getRollbackRules().add(new RollbackRuleAttribute(Exception.class)); - rbta.getRollbackRules().add(new NoRollbackRuleAttribute(IOException.class)); - assertThat(((RuleBasedTransactionAttribute) actual).getRollbackRules()).isEqualTo(rbta.getRollbackRules()); - + void customMethodAttributeWithReadOnlyOverrideDetected() { + TransactionAttribute actual = getTransactionAttribute(TestBean8.class, "getAge"); + assertThat(actual).satisfies(hasRollbackRules(new RollbackRuleAttribute(Exception.class), + new NoRollbackRuleAttribute(IOException.class))); assertThat(actual.isReadOnly()).isTrue(); } @Test - void customClassAttributeWithReadOnlyOverrideOnInterface() throws Exception { - Method method = TestInterface9.class.getMethod("getAge"); + void customClassAttributeWithReadOnlyOverrideOnInterface() { + Method method = getMethod(TestInterface9.class, "getAge"); Transactional annotation = AnnotationUtils.findAnnotation(method, Transactional.class); assertThat(annotation).as("AnnotationUtils.findAnnotation should not find @Transactional for TestBean9.getAge()").isNull(); annotation = AnnotationUtils.findAnnotation(TestBean9.class, Transactional.class); assertThat(annotation).as("AnnotationUtils.findAnnotation failed to find @Transactional for TestBean9").isNotNull(); - AnnotationTransactionAttributeSource atas = new AnnotationTransactionAttributeSource(); - TransactionAttribute actual = atas.getTransactionAttribute(method, TestBean9.class); - assertThat(actual).as("Failed to retrieve TransactionAttribute for TestBean9.getAge()").isNotNull(); - - RuleBasedTransactionAttribute rbta = new RuleBasedTransactionAttribute(); - rbta.getRollbackRules().add(new RollbackRuleAttribute(Exception.class)); - rbta.getRollbackRules().add(new NoRollbackRuleAttribute(IOException.class)); - assertThat(((RuleBasedTransactionAttribute) actual).getRollbackRules()).isEqualTo(rbta.getRollbackRules()); - + TransactionAttribute actual = getTransactionAttribute(TestBean9.class, method); + assertThat(actual).satisfies(hasRollbackRules(new RollbackRuleAttribute(Exception.class), + new NoRollbackRuleAttribute(IOException.class))); assertThat(actual.isReadOnly()).isTrue(); } @Test - void customMethodAttributeWithReadOnlyOverrideOnInterface() throws Exception { - Method method = TestInterface10.class.getMethod("getAge"); + void customMethodAttributeWithReadOnlyOverrideOnInterface() { + Method method = getMethod(TestInterface10.class, "getAge"); Transactional annotation = AnnotationUtils.findAnnotation(method, Transactional.class); assertThat(annotation).as("AnnotationUtils.findAnnotation failed to find @Transactional for TestBean10.getAge()").isNotNull(); annotation = AnnotationUtils.findAnnotation(TestBean10.class, Transactional.class); assertThat(annotation).as("AnnotationUtils.findAnnotation should not find @Transactional for TestBean10").isNull(); - AnnotationTransactionAttributeSource atas = new AnnotationTransactionAttributeSource(); - TransactionAttribute actual = atas.getTransactionAttribute(method, TestBean10.class); - assertThat(actual).as("Failed to retrieve TransactionAttribute for TestBean10.getAge()").isNotNull(); - - RuleBasedTransactionAttribute rbta = new RuleBasedTransactionAttribute(); - rbta.getRollbackRules().add(new RollbackRuleAttribute(Exception.class)); - rbta.getRollbackRules().add(new NoRollbackRuleAttribute(IOException.class)); - assertThat(((RuleBasedTransactionAttribute) actual).getRollbackRules()).isEqualTo(rbta.getRollbackRules()); - + TransactionAttribute actual = getTransactionAttribute(TestBean10.class, method); + assertThat(actual).satisfies(hasRollbackRules(new RollbackRuleAttribute(Exception.class), + new NoRollbackRuleAttribute(IOException.class))); assertThat(actual.isReadOnly()).isTrue(); } - @Test - void transactionAttributeDeclaredOnClassMethodWithEjb3() throws Exception { - Method getAgeMethod = ITestBean1.class.getMethod("getAge"); - Method getNameMethod = ITestBean1.class.getMethod("getName"); + @Nested + class JtaAttributeTests { - AnnotationTransactionAttributeSource atas = new AnnotationTransactionAttributeSource(); - TransactionAttribute getAgeAttr = atas.getTransactionAttribute(getAgeMethod, Ejb3AnnotatedBean1.class); - assertThat(getAgeAttr.getPropagationBehavior()).isEqualTo(TransactionAttribute.PROPAGATION_REQUIRED); - TransactionAttribute getNameAttr = atas.getTransactionAttribute(getNameMethod, Ejb3AnnotatedBean1.class); - assertThat(getNameAttr.getPropagationBehavior()).isEqualTo(TransactionAttribute.PROPAGATION_SUPPORTS); - } + @Test + void transactionAttributeDeclaredOnClassMethod() { + TransactionAttribute getAgeAttr = getTransactionAttribute(JtaAnnotatedBean1.class, ITestBean1.class, "getAge"); + assertThat(getAgeAttr.getPropagationBehavior()).isEqualTo(TransactionAttribute.PROPAGATION_REQUIRED); + TransactionAttribute getNameAttr = getTransactionAttribute(JtaAnnotatedBean1.class, ITestBean1.class, "getName"); + assertThat(getNameAttr.getPropagationBehavior()).isEqualTo(TransactionAttribute.PROPAGATION_SUPPORTS); + } - @Test - void transactionAttributeDeclaredOnClassWithEjb3() throws Exception { - Method getAgeMethod = ITestBean1.class.getMethod("getAge"); - Method getNameMethod = ITestBean1.class.getMethod("getName"); + @Test + void transactionAttributeDeclaredOnClass() { + TransactionAttribute getAgeAttr = getTransactionAttribute(JtaAnnotatedBean2.class, ITestBean1.class, "getAge"); + assertThat(getAgeAttr.getPropagationBehavior()).isEqualTo(TransactionAttribute.PROPAGATION_REQUIRED); + TransactionAttribute getNameAttr = getTransactionAttribute(JtaAnnotatedBean2.class, ITestBean1.class, "getName"); + assertThat(getNameAttr.getPropagationBehavior()).isEqualTo(TransactionAttribute.PROPAGATION_SUPPORTS); + } + + @Test + void transactionAttributeDeclaredOnInterface() { + TransactionAttribute getAgeAttr = getTransactionAttribute(JtaAnnotatedBean3.class, ITestJta.class, "getAge"); + assertThat(getAgeAttr.getPropagationBehavior()).isEqualTo(TransactionAttribute.PROPAGATION_REQUIRED); + TransactionAttribute getNameAttr = getTransactionAttribute(JtaAnnotatedBean3.class, ITestJta.class, "getName"); + assertThat(getNameAttr.getPropagationBehavior()).isEqualTo(TransactionAttribute.PROPAGATION_SUPPORTS); + } + + static class JtaAnnotatedBean1 implements ITestBean1 { + + private String name; + + private int age; + + @Override + @jakarta.transaction.Transactional(jakarta.transaction.Transactional.TxType.SUPPORTS) + public String getName() { + return name; + } + + @Override + public void setName(String name) { + this.name = name; + } + + @Override + @jakarta.transaction.Transactional + public int getAge() { + return age; + } + + @Override + public void setAge(int age) { + this.age = age; + } + } + + + @jakarta.transaction.Transactional(jakarta.transaction.Transactional.TxType.SUPPORTS) + static class JtaAnnotatedBean2 implements ITestBean1 { + + private String name; + + private int age; + + @Override + public String getName() { + return name; + } + + @Override + public void setName(String name) { + this.name = name; + } + + @Override + @jakarta.transaction.Transactional + public int getAge() { + return age; + } + + @Override + public void setAge(int age) { + this.age = age; + } + } + + static class JtaAnnotatedBean3 implements ITestJta { + + private String name; + + private int age; + + @Override + public String getName() { + return name; + } + + @Override + public void setName(String name) { + this.name = name; + } + + @Override + public int getAge() { + return age; + } + + @Override + public void setAge(int age) { + this.age = age; + } + } + + + @jakarta.transaction.Transactional(jakarta.transaction.Transactional.TxType.SUPPORTS) + interface ITestJta { + + @jakarta.transaction.Transactional + int getAge(); + + void setAge(int age); + + String getName(); + + void setName(String name); + } - AnnotationTransactionAttributeSource atas = new AnnotationTransactionAttributeSource(); - TransactionAttribute getAgeAttr = atas.getTransactionAttribute(getAgeMethod, Ejb3AnnotatedBean2.class); - assertThat(getAgeAttr.getPropagationBehavior()).isEqualTo(TransactionAttribute.PROPAGATION_REQUIRED); - TransactionAttribute getNameAttr = atas.getTransactionAttribute(getNameMethod, Ejb3AnnotatedBean2.class); - assertThat(getNameAttr.getPropagationBehavior()).isEqualTo(TransactionAttribute.PROPAGATION_SUPPORTS); } - @Test - void transactionAttributeDeclaredOnInterfaceWithEjb3() throws Exception { - Method getAgeMethod = ITestEjb.class.getMethod("getAge"); - Method getNameMethod = ITestEjb.class.getMethod("getName"); + @Nested + class Ejb3AttributeTests { + + @Test + void transactionAttributeDeclaredOnClassMethod() { + TransactionAttribute getAgeAttr = getTransactionAttribute(Ejb3AnnotatedBean1.class, ITestBean1.class, "getAge"); + assertThat(getAgeAttr.getPropagationBehavior()).isEqualTo(TransactionAttribute.PROPAGATION_REQUIRED); + TransactionAttribute getNameAttr = getTransactionAttribute(Ejb3AnnotatedBean1.class, ITestBean1.class, "getName"); + assertThat(getNameAttr.getPropagationBehavior()).isEqualTo(TransactionAttribute.PROPAGATION_SUPPORTS); + } + + @Test + void transactionAttributeDeclaredOnClass() { + TransactionAttribute getAgeAttr = getTransactionAttribute(Ejb3AnnotatedBean2.class, ITestBean1.class, "getAge"); + assertThat(getAgeAttr.getPropagationBehavior()).isEqualTo(TransactionAttribute.PROPAGATION_REQUIRED); + TransactionAttribute getNameAttr = getTransactionAttribute(Ejb3AnnotatedBean2.class, ITestBean1.class, "getName"); + assertThat(getNameAttr.getPropagationBehavior()).isEqualTo(TransactionAttribute.PROPAGATION_SUPPORTS); + } + + @Test + void transactionAttributeDeclaredOnInterface() { + TransactionAttribute getAgeAttr = getTransactionAttribute(Ejb3AnnotatedBean3.class, ITestEjb.class, "getAge"); + assertThat(getAgeAttr.getPropagationBehavior()).isEqualTo(TransactionAttribute.PROPAGATION_REQUIRED); + TransactionAttribute getNameAttr = getTransactionAttribute(Ejb3AnnotatedBean3.class, ITestEjb.class, "getName"); + assertThat(getNameAttr.getPropagationBehavior()).isEqualTo(TransactionAttribute.PROPAGATION_SUPPORTS); + } + + + @jakarta.ejb.TransactionAttribute(TransactionAttributeType.SUPPORTS) + interface ITestEjb { + + @jakarta.ejb.TransactionAttribute + int getAge(); + + void setAge(int age); + + String getName(); + + void setName(String name); + } + + static class Ejb3AnnotatedBean1 implements ITestBean1 { - AnnotationTransactionAttributeSource atas = new AnnotationTransactionAttributeSource(); - TransactionAttribute getAgeAttr = atas.getTransactionAttribute(getAgeMethod, Ejb3AnnotatedBean3.class); - assertThat(getAgeAttr.getPropagationBehavior()).isEqualTo(TransactionAttribute.PROPAGATION_REQUIRED); - TransactionAttribute getNameAttr = atas.getTransactionAttribute(getNameMethod, Ejb3AnnotatedBean3.class); - assertThat(getNameAttr.getPropagationBehavior()).isEqualTo(TransactionAttribute.PROPAGATION_SUPPORTS); + private String name; + + private int age; + + @Override + @jakarta.ejb.TransactionAttribute(TransactionAttributeType.SUPPORTS) + public String getName() { + return name; + } + + @Override + public void setName(String name) { + this.name = name; + } + + @Override + @jakarta.ejb.TransactionAttribute + public int getAge() { + return age; + } + + @Override + public void setAge(int age) { + this.age = age; + } + } + + + @jakarta.ejb.TransactionAttribute(TransactionAttributeType.SUPPORTS) + static class Ejb3AnnotatedBean2 implements ITestBean1 { + + private String name; + + private int age; + + @Override + public String getName() { + return name; + } + + @Override + public void setName(String name) { + this.name = name; + } + + @Override + @jakarta.ejb.TransactionAttribute + public int getAge() { + return age; + } + + @Override + public void setAge(int age) { + this.age = age; + } + } + + static class Ejb3AnnotatedBean3 implements ITestEjb { + + private String name; + + private int age; + + @Override + public String getName() { + return name; + } + + @Override + public void setName(String name) { + this.name = name; + } + + @Override + public int getAge() { + return age; + } + + @Override + public void setAge(int age) { + this.age = age; + } + } } - @Test - void transactionAttributeDeclaredOnClassMethodWithJta() throws Exception { - Method getAgeMethod = ITestBean1.class.getMethod("getAge"); - Method getNameMethod = ITestBean1.class.getMethod("getName"); + @Nested + class GroovyTests { + + @Test + void transactionAttributeDeclaredOnGroovyClass() { + TransactionAttribute getAgeAttr = getTransactionAttribute(GroovyTestBean.class, ITestBean1.class, "getAge"); + assertThat(getAgeAttr.getPropagationBehavior()).isEqualTo(TransactionAttribute.PROPAGATION_REQUIRED); + TransactionAttribute getNameAttr = getTransactionAttribute(GroovyTestBean.class, ITestBean1.class, "getName"); + assertThat(getNameAttr.getPropagationBehavior()).isEqualTo(TransactionAttribute.PROPAGATION_REQUIRED); + Method getMetaClassMethod = getMethod(GroovyObject.class, "getMetaClass"); + assertThat(attributeSource.getTransactionAttribute(getMetaClassMethod, GroovyTestBean.class)).isNull(); + } + + @Transactional + static class GroovyTestBean implements ITestBean1, GroovyObject { + + private String name; + + private int age; + + @Override + public String getName() { + return name; + } + + @Override + public void setName(String name) { + this.name = name; + } + + @Override + public int getAge() { + return age; + } + + @Override + public void setAge(int age) { + this.age = age; + } - AnnotationTransactionAttributeSource atas = new AnnotationTransactionAttributeSource(); - TransactionAttribute getAgeAttr = atas.getTransactionAttribute(getAgeMethod, JtaAnnotatedBean1.class); - assertThat(getAgeAttr.getPropagationBehavior()).isEqualTo(TransactionAttribute.PROPAGATION_REQUIRED); - TransactionAttribute getNameAttr = atas.getTransactionAttribute(getNameMethod, JtaAnnotatedBean1.class); - assertThat(getNameAttr.getPropagationBehavior()).isEqualTo(TransactionAttribute.PROPAGATION_SUPPORTS); + @Override + public Object invokeMethod(String name, Object args) { + return null; + } + + @Override + public Object getProperty(String propertyName) { + return null; + } + + @Override + public void setProperty(String propertyName, Object newValue) { + } + + @Override + public MetaClass getMetaClass() { + return null; + } + + @Override + public void setMetaClass(MetaClass metaClass) { + } + } } - @Test - void transactionAttributeDeclaredOnClassWithJta() throws Exception { - Method getAgeMethod = ITestBean1.class.getMethod("getAge"); - Method getNameMethod = ITestBean1.class.getMethod("getName"); + private Consumer hasRollbackRules(RollbackRuleAttribute... rollbackRuleAttributes) { + return transactionAttribute -> { + RuleBasedTransactionAttribute rbta = new RuleBasedTransactionAttribute(); + rbta.getRollbackRules().addAll(Arrays.asList(rollbackRuleAttributes)); + assertThat(transactionAttribute).isInstanceOfSatisfying(RuleBasedTransactionAttribute.class, + attribute -> assertThat(attribute.getRollbackRules()).isEqualTo(rbta.getRollbackRules())); + }; + } - AnnotationTransactionAttributeSource atas = new AnnotationTransactionAttributeSource(); - TransactionAttribute getAgeAttr = atas.getTransactionAttribute(getAgeMethod, JtaAnnotatedBean2.class); - assertThat(getAgeAttr.getPropagationBehavior()).isEqualTo(TransactionAttribute.PROPAGATION_REQUIRED); - TransactionAttribute getNameAttr = atas.getTransactionAttribute(getNameMethod, JtaAnnotatedBean2.class); - assertThat(getNameAttr.getPropagationBehavior()).isEqualTo(TransactionAttribute.PROPAGATION_SUPPORTS); + private Consumer hasNoRollbackRule() { + return hasRollbackRules(); } - @Test - void transactionAttributeDeclaredOnInterfaceWithJta() throws Exception { - Method getAgeMethod = ITestEjb.class.getMethod("getAge"); - Method getNameMethod = ITestEjb.class.getMethod("getName"); + private TransactionAttribute getTransactionAttribute(Class targetType, Method method) { + TransactionAttribute transactionAttribute = this.attributeSource.getTransactionAttribute(method, targetType); + assertThat(transactionAttribute).isNotNull(); + return transactionAttribute; + } - AnnotationTransactionAttributeSource atas = new AnnotationTransactionAttributeSource(); - TransactionAttribute getAgeAttr = atas.getTransactionAttribute(getAgeMethod, JtaAnnotatedBean3.class); - assertThat(getAgeAttr.getPropagationBehavior()).isEqualTo(TransactionAttribute.PROPAGATION_REQUIRED); - TransactionAttribute getNameAttr = atas.getTransactionAttribute(getNameMethod, JtaAnnotatedBean3.class); - assertThat(getNameAttr.getPropagationBehavior()).isEqualTo(TransactionAttribute.PROPAGATION_SUPPORTS); + private TransactionAttribute getTransactionAttribute(Class targetType, Class declaringType, String methodName, Class... parameterTypes) { + return getTransactionAttribute(targetType, getMethod(declaringType, methodName, parameterTypes)); } - @Test - void transactionAttributeDeclaredOnGroovyClass() throws Exception { - Method getAgeMethod = ITestBean1.class.getMethod("getAge"); - Method getNameMethod = ITestBean1.class.getMethod("getName"); - Method getMetaClassMethod = GroovyObject.class.getMethod("getMetaClass"); + private TransactionAttribute getTransactionAttribute(Class declaringType, String methodName, Class... parameterTypes) { + return getTransactionAttribute(declaringType, declaringType, methodName, parameterTypes); + } - AnnotationTransactionAttributeSource atas = new AnnotationTransactionAttributeSource(); - TransactionAttribute getAgeAttr = atas.getTransactionAttribute(getAgeMethod, GroovyTestBean.class); - assertThat(getAgeAttr.getPropagationBehavior()).isEqualTo(TransactionAttribute.PROPAGATION_REQUIRED); - TransactionAttribute getNameAttr = atas.getTransactionAttribute(getNameMethod, GroovyTestBean.class); - assertThat(getNameAttr.getPropagationBehavior()).isEqualTo(TransactionAttribute.PROPAGATION_REQUIRED); - assertThat(atas.getTransactionAttribute(getMetaClassMethod, GroovyTestBean.class)).isNull(); + private Method getMethod(Class declaringType, String methodName, Class... parameterTypes) { + Method method = ReflectionUtils.findMethod(declaringType, methodName, parameterTypes); + assertThat(method).isNotNull(); + return method; } @@ -738,260 +932,4 @@ class AnnotationTransactionAttributeSourceTests { } } - - static class Ejb3AnnotatedBean1 implements ITestBean1 { - - private String name; - - private int age; - - @Override - @jakarta.ejb.TransactionAttribute(TransactionAttributeType.SUPPORTS) - public String getName() { - return name; - } - - @Override - public void setName(String name) { - this.name = name; - } - - @Override - @jakarta.ejb.TransactionAttribute - public int getAge() { - return age; - } - - @Override - public void setAge(int age) { - this.age = age; - } - } - - - @jakarta.ejb.TransactionAttribute(TransactionAttributeType.SUPPORTS) - static class Ejb3AnnotatedBean2 implements ITestBean1 { - - private String name; - - private int age; - - @Override - public String getName() { - return name; - } - - @Override - public void setName(String name) { - this.name = name; - } - - @Override - @jakarta.ejb.TransactionAttribute - public int getAge() { - return age; - } - - @Override - public void setAge(int age) { - this.age = age; - } - } - - - @jakarta.ejb.TransactionAttribute(TransactionAttributeType.SUPPORTS) - interface ITestEjb { - - @jakarta.ejb.TransactionAttribute - int getAge(); - - void setAge(int age); - - String getName(); - - void setName(String name); - } - - - static class Ejb3AnnotatedBean3 implements ITestEjb { - - private String name; - - private int age; - - @Override - public String getName() { - return name; - } - - @Override - public void setName(String name) { - this.name = name; - } - - @Override - public int getAge() { - return age; - } - - @Override - public void setAge(int age) { - this.age = age; - } - } - - - static class JtaAnnotatedBean1 implements ITestBean1 { - - private String name; - - private int age; - - @Override - @jakarta.transaction.Transactional(jakarta.transaction.Transactional.TxType.SUPPORTS) - public String getName() { - return name; - } - - @Override - public void setName(String name) { - this.name = name; - } - - @Override - @jakarta.transaction.Transactional - public int getAge() { - return age; - } - - @Override - public void setAge(int age) { - this.age = age; - } - } - - - @jakarta.transaction.Transactional(jakarta.transaction.Transactional.TxType.SUPPORTS) - static class JtaAnnotatedBean2 implements ITestBean1 { - - private String name; - - private int age; - - @Override - public String getName() { - return name; - } - - @Override - public void setName(String name) { - this.name = name; - } - - @Override - @jakarta.transaction.Transactional - public int getAge() { - return age; - } - - @Override - public void setAge(int age) { - this.age = age; - } - } - - - @jakarta.transaction.Transactional(jakarta.transaction.Transactional.TxType.SUPPORTS) - interface ITestJta { - - @jakarta.transaction.Transactional - int getAge(); - - void setAge(int age); - - String getName(); - - void setName(String name); - } - - - static class JtaAnnotatedBean3 implements ITestEjb { - - private String name; - - private int age; - - @Override - public String getName() { - return name; - } - - @Override - public void setName(String name) { - this.name = name; - } - - @Override - public int getAge() { - return age; - } - - @Override - public void setAge(int age) { - this.age = age; - } - } - - - @Transactional - static class GroovyTestBean implements ITestBean1, GroovyObject { - - private String name; - - private int age; - - @Override - public String getName() { - return name; - } - - @Override - public void setName(String name) { - this.name = name; - } - - @Override - public int getAge() { - return age; - } - - @Override - public void setAge(int age) { - this.age = age; - } - - @Override - public Object invokeMethod(String name, Object args) { - return null; - } - - @Override - public Object getProperty(String propertyName) { - return null; - } - - @Override - public void setProperty(String propertyName, Object newValue) { - } - - @Override - public MetaClass getMetaClass() { - return null; - } - - @Override - public void setMetaClass(MetaClass metaClass) { - } - } - }