custom stereotype annotations can be meta-annotated with @Service, @Controller etc as well; @Scope and @Transactional are now supported as meta-annotations on custom annotations
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2008 the original author or authors.
|
||||
* Copyright 2002-2009 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -18,6 +18,7 @@ package org.springframework.transaction.annotation;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.lang.reflect.AnnotatedElement;
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.util.ArrayList;
|
||||
|
||||
import org.springframework.transaction.interceptor.NoRollbackRuleAttribute;
|
||||
@@ -35,6 +36,14 @@ public class SpringTransactionAnnotationParser implements TransactionAnnotationP
|
||||
|
||||
public TransactionAttribute parseTransactionAnnotation(AnnotatedElement ae) {
|
||||
Transactional ann = ae.getAnnotation(Transactional.class);
|
||||
if (ann == null) {
|
||||
for (Annotation metaAnn : ae.getAnnotations()) {
|
||||
ann = metaAnn.annotationType().getAnnotation(Transactional.class);
|
||||
if (ann != null) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (ann != null) {
|
||||
return parseTransactionAnnotation(ann);
|
||||
}
|
||||
@@ -51,23 +60,23 @@ public class SpringTransactionAnnotationParser implements TransactionAnnotationP
|
||||
rbta.setReadOnly(ann.readOnly());
|
||||
ArrayList<RollbackRuleAttribute> rollBackRules = new ArrayList<RollbackRuleAttribute>();
|
||||
Class[] rbf = ann.rollbackFor();
|
||||
for (int i = 0; i < rbf.length; ++i) {
|
||||
RollbackRuleAttribute rule = new RollbackRuleAttribute(rbf[i]);
|
||||
for (Class rbRule : rbf) {
|
||||
RollbackRuleAttribute rule = new RollbackRuleAttribute(rbRule);
|
||||
rollBackRules.add(rule);
|
||||
}
|
||||
String[] rbfc = ann.rollbackForClassName();
|
||||
for (int i = 0; i < rbfc.length; ++i) {
|
||||
RollbackRuleAttribute rule = new RollbackRuleAttribute(rbfc[i]);
|
||||
for (String rbRule : rbfc) {
|
||||
RollbackRuleAttribute rule = new RollbackRuleAttribute(rbRule);
|
||||
rollBackRules.add(rule);
|
||||
}
|
||||
Class[] nrbf = ann.noRollbackFor();
|
||||
for (int i = 0; i < nrbf.length; ++i) {
|
||||
NoRollbackRuleAttribute rule = new NoRollbackRuleAttribute(nrbf[i]);
|
||||
for (Class rbRule : nrbf) {
|
||||
NoRollbackRuleAttribute rule = new NoRollbackRuleAttribute(rbRule);
|
||||
rollBackRules.add(rule);
|
||||
}
|
||||
String[] nrbfc = ann.noRollbackForClassName();
|
||||
for (int i = 0; i < nrbfc.length; ++i) {
|
||||
NoRollbackRuleAttribute rule = new NoRollbackRuleAttribute(nrbfc[i]);
|
||||
for (String rbRule : nrbfc) {
|
||||
NoRollbackRuleAttribute rule = new NoRollbackRuleAttribute(rbRule);
|
||||
rollBackRules.add(rule);
|
||||
}
|
||||
rbta.getRollbackRules().addAll(rollBackRules);
|
||||
|
||||
@@ -18,11 +18,15 @@ package org.springframework.transaction.annotation;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.Serializable;
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
import javax.ejb.TransactionAttributeType;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
import static org.junit.Assert.*;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.springframework.aop.framework.Advised;
|
||||
import org.springframework.aop.framework.ProxyFactory;
|
||||
@@ -38,8 +42,9 @@ import org.springframework.util.SerializationTestUtils;
|
||||
* @author Colin Sampaleanu
|
||||
* @author Juergen Hoeller
|
||||
*/
|
||||
public class AnnotationTransactionAttributeSourceTests extends TestCase {
|
||||
public class AnnotationTransactionAttributeSourceTests {
|
||||
|
||||
@Test
|
||||
public void testSerializable() throws Exception {
|
||||
TestBean1 tb = new TestBean1();
|
||||
CallCountingTransactionManager ptm = new CallCountingTransactionManager();
|
||||
@@ -63,6 +68,7 @@ public class AnnotationTransactionAttributeSourceTests extends TestCase {
|
||||
assertEquals(2, serializedPtm.commits);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNullOrEmpty() throws Exception {
|
||||
Method method = Empty.class.getMethod("getAge", (Class[]) null);
|
||||
|
||||
@@ -77,6 +83,7 @@ public class AnnotationTransactionAttributeSourceTests extends TestCase {
|
||||
* Test the important case where the invocation is on a proxied interface method
|
||||
* but the attribute is defined on the target class.
|
||||
*/
|
||||
@Test
|
||||
public void testTransactionAttributeDeclaredOnClassMethod() throws Exception {
|
||||
Method classMethod = ITestBean.class.getMethod("getAge", (Class[]) null);
|
||||
|
||||
@@ -91,6 +98,7 @@ public class AnnotationTransactionAttributeSourceTests extends TestCase {
|
||||
/**
|
||||
* Test case where attribute is on the interface method.
|
||||
*/
|
||||
@Test
|
||||
public void testTransactionAttributeDeclaredOnInterfaceMethodOnly() throws Exception {
|
||||
Method interfaceMethod = ITestBean2.class.getMethod("getAge", (Class[]) null);
|
||||
|
||||
@@ -104,6 +112,7 @@ public class AnnotationTransactionAttributeSourceTests extends TestCase {
|
||||
/**
|
||||
* Test that when an attribute exists on both class and interface, class takes precedence.
|
||||
*/
|
||||
@Test
|
||||
public void testTransactionAttributeOnTargetClassMethodOverridesAttributeOnInterfaceMethod() throws Exception {
|
||||
Method interfaceMethod = ITestBean3.class.getMethod("getAge", (Class[]) null);
|
||||
Method interfaceMethod2 = ITestBean3.class.getMethod("getName", (Class[]) null);
|
||||
@@ -124,6 +133,7 @@ public class AnnotationTransactionAttributeSourceTests extends TestCase {
|
||||
assertEquals(TransactionAttribute.PROPAGATION_REQUIRED, actual2.getPropagationBehavior());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRollbackRulesAreApplied() throws Exception {
|
||||
Method method = TestBean3.class.getMethod("getAge", (Class[]) null);
|
||||
|
||||
@@ -153,6 +163,7 @@ public class AnnotationTransactionAttributeSourceTests extends TestCase {
|
||||
* Test that transaction attribute is inherited from class
|
||||
* if not specified on method.
|
||||
*/
|
||||
@Test
|
||||
public void testDefaultsToClassTransactionAttribute() throws Exception {
|
||||
Method method = TestBean4.class.getMethod("getAge", (Class[]) null);
|
||||
|
||||
@@ -165,6 +176,33 @@ public class AnnotationTransactionAttributeSourceTests extends TestCase {
|
||||
assertEquals(rbta.getRollbackRules(), ((RuleBasedTransactionAttribute) actual).getRollbackRules());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCustomClassAttributeDetected() throws Exception {
|
||||
Method method = TestBean5.class.getMethod("getAge", (Class[]) null);
|
||||
|
||||
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));
|
||||
assertEquals(rbta.getRollbackRules(), ((RuleBasedTransactionAttribute) actual).getRollbackRules());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCustomMethodAttributeDetected() throws Exception {
|
||||
Method method = TestBean6.class.getMethod("getAge", (Class[]) null);
|
||||
|
||||
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));
|
||||
assertEquals(rbta.getRollbackRules(), ((RuleBasedTransactionAttribute) actual).getRollbackRules());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTransactionAttributeDeclaredOnClassMethodWithEjb3() throws Exception {
|
||||
Method getAgeMethod = ITestBean.class.getMethod("getAge", (Class[]) null);
|
||||
Method getNameMethod = ITestBean.class.getMethod("getName", (Class[]) null);
|
||||
@@ -176,6 +214,7 @@ public class AnnotationTransactionAttributeSourceTests extends TestCase {
|
||||
assertEquals(TransactionAttribute.PROPAGATION_SUPPORTS, getNameAttr.getPropagationBehavior());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTransactionAttributeDeclaredOnClassWithEjb3() throws Exception {
|
||||
Method getAgeMethod = ITestBean.class.getMethod("getAge", (Class[]) null);
|
||||
Method getNameMethod = ITestBean.class.getMethod("getName", (Class[]) null);
|
||||
@@ -187,6 +226,7 @@ public class AnnotationTransactionAttributeSourceTests extends TestCase {
|
||||
assertEquals(TransactionAttribute.PROPAGATION_SUPPORTS, getNameAttr.getPropagationBehavior());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTransactionAttributeDeclaredOnInterfaceWithEjb3() throws Exception {
|
||||
Method getAgeMethod = ITestEjb.class.getMethod("getAge", (Class[]) null);
|
||||
Method getNameMethod = ITestEjb.class.getMethod("getName", (Class[]) null);
|
||||
@@ -401,6 +441,31 @@ public class AnnotationTransactionAttributeSourceTests extends TestCase {
|
||||
}
|
||||
|
||||
|
||||
@Target({ElementType.TYPE, ElementType.METHOD})
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Transactional(rollbackFor=Exception.class, noRollbackFor={IOException.class})
|
||||
public @interface Tx {
|
||||
}
|
||||
|
||||
|
||||
@Tx
|
||||
public static class TestBean5 {
|
||||
|
||||
public int getAge() {
|
||||
return 10;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static class TestBean6 {
|
||||
|
||||
@Tx
|
||||
public int getAge() {
|
||||
return 10;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static interface Foo<T> {
|
||||
|
||||
void doSomething(T theArgument);
|
||||
|
||||
Reference in New Issue
Block a user