Allow meta-annotations to override attributes from their parent
Issue: SPR-10181
This commit is contained in:
@@ -20,7 +20,9 @@ import java.io.Serializable;
|
||||
import java.lang.reflect.AnnotatedElement;
|
||||
import java.util.ArrayList;
|
||||
|
||||
import org.springframework.core.annotation.AnnotationAttributes;
|
||||
import org.springframework.core.annotation.AnnotationUtils;
|
||||
import org.springframework.core.annotation.AnnotatedElementUtils;
|
||||
import org.springframework.transaction.interceptor.NoRollbackRuleAttribute;
|
||||
import org.springframework.transaction.interceptor.RollbackRuleAttribute;
|
||||
import org.springframework.transaction.interceptor.RuleBasedTransactionAttribute;
|
||||
@@ -37,7 +39,7 @@ public class JtaTransactionAnnotationParser implements TransactionAnnotationPars
|
||||
|
||||
@Override
|
||||
public TransactionAttribute parseTransactionAnnotation(AnnotatedElement ae) {
|
||||
javax.transaction.Transactional ann = AnnotationUtils.getAnnotation(ae, javax.transaction.Transactional.class);
|
||||
AnnotationAttributes ann = AnnotatedElementUtils.getAnnotationAttributes(ae, javax.transaction.Transactional.class.getName());
|
||||
if (ann != null) {
|
||||
return parseTransactionAnnotation(ann);
|
||||
}
|
||||
@@ -47,15 +49,20 @@ public class JtaTransactionAnnotationParser implements TransactionAnnotationPars
|
||||
}
|
||||
|
||||
public TransactionAttribute parseTransactionAnnotation(javax.transaction.Transactional ann) {
|
||||
return parseTransactionAnnotation(AnnotationUtils.getAnnotationAttributes(ann, false, false));
|
||||
}
|
||||
|
||||
protected TransactionAttribute parseTransactionAnnotation(AnnotationAttributes attributes) {
|
||||
RuleBasedTransactionAttribute rbta = new RuleBasedTransactionAttribute();
|
||||
rbta.setPropagationBehaviorName(RuleBasedTransactionAttribute.PREFIX_PROPAGATION + ann.value().toString());
|
||||
rbta.setPropagationBehaviorName(
|
||||
RuleBasedTransactionAttribute.PREFIX_PROPAGATION + attributes.getEnum("value").toString());
|
||||
ArrayList<RollbackRuleAttribute> rollBackRules = new ArrayList<RollbackRuleAttribute>();
|
||||
Class[] rbf = ann.rollbackOn();
|
||||
Class[] rbf = attributes.getClassArray("rollbackOn");
|
||||
for (Class rbRule : rbf) {
|
||||
RollbackRuleAttribute rule = new RollbackRuleAttribute(rbRule);
|
||||
rollBackRules.add(rule);
|
||||
}
|
||||
Class[] nrbf = ann.dontRollbackOn();
|
||||
Class[] nrbf = attributes.getClassArray("dontRollbackOn");
|
||||
for (Class rbRule : nrbf) {
|
||||
NoRollbackRuleAttribute rule = new NoRollbackRuleAttribute(rbRule);
|
||||
rollBackRules.add(rule);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2013 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.
|
||||
@@ -20,7 +20,9 @@ import java.io.Serializable;
|
||||
import java.lang.reflect.AnnotatedElement;
|
||||
import java.util.ArrayList;
|
||||
|
||||
import org.springframework.core.annotation.AnnotationAttributes;
|
||||
import org.springframework.core.annotation.AnnotationUtils;
|
||||
import org.springframework.core.annotation.AnnotatedElementUtils;
|
||||
import org.springframework.transaction.interceptor.NoRollbackRuleAttribute;
|
||||
import org.springframework.transaction.interceptor.RollbackRuleAttribute;
|
||||
import org.springframework.transaction.interceptor.RuleBasedTransactionAttribute;
|
||||
@@ -37,7 +39,7 @@ public class SpringTransactionAnnotationParser implements TransactionAnnotationP
|
||||
|
||||
@Override
|
||||
public TransactionAttribute parseTransactionAnnotation(AnnotatedElement ae) {
|
||||
Transactional ann = AnnotationUtils.getAnnotation(ae, Transactional.class);
|
||||
AnnotationAttributes ann = AnnotatedElementUtils.getAnnotationAttributes(ae, Transactional.class.getName());
|
||||
if (ann != null) {
|
||||
return parseTransactionAnnotation(ann);
|
||||
}
|
||||
@@ -47,29 +49,35 @@ public class SpringTransactionAnnotationParser implements TransactionAnnotationP
|
||||
}
|
||||
|
||||
public TransactionAttribute parseTransactionAnnotation(Transactional ann) {
|
||||
return parseTransactionAnnotation(AnnotationUtils.getAnnotationAttributes(ann, false, false));
|
||||
}
|
||||
|
||||
protected TransactionAttribute parseTransactionAnnotation(AnnotationAttributes attributes) {
|
||||
RuleBasedTransactionAttribute rbta = new RuleBasedTransactionAttribute();
|
||||
rbta.setPropagationBehavior(ann.propagation().value());
|
||||
rbta.setIsolationLevel(ann.isolation().value());
|
||||
rbta.setTimeout(ann.timeout());
|
||||
rbta.setReadOnly(ann.readOnly());
|
||||
rbta.setQualifier(ann.value());
|
||||
Propagation propagation = attributes.getEnum("propagation");
|
||||
rbta.setPropagationBehavior(propagation.value());
|
||||
Isolation isolation = attributes.getEnum("isolation");
|
||||
rbta.setIsolationLevel(isolation.value());
|
||||
rbta.setTimeout(attributes.getNumber("timeout").intValue());
|
||||
rbta.setReadOnly(attributes.getBoolean("readOnly"));
|
||||
rbta.setQualifier(attributes.getString("value"));
|
||||
ArrayList<RollbackRuleAttribute> rollBackRules = new ArrayList<RollbackRuleAttribute>();
|
||||
Class[] rbf = ann.rollbackFor();
|
||||
Class[] rbf = attributes.getClassArray("rollbackFor");
|
||||
for (Class rbRule : rbf) {
|
||||
RollbackRuleAttribute rule = new RollbackRuleAttribute(rbRule);
|
||||
rollBackRules.add(rule);
|
||||
}
|
||||
String[] rbfc = ann.rollbackForClassName();
|
||||
String[] rbfc = attributes.getStringArray("rollbackForClassName");
|
||||
for (String rbRule : rbfc) {
|
||||
RollbackRuleAttribute rule = new RollbackRuleAttribute(rbRule);
|
||||
rollBackRules.add(rule);
|
||||
}
|
||||
Class[] nrbf = ann.noRollbackFor();
|
||||
Class[] nrbf = attributes.getClassArray("noRollbackFor");
|
||||
for (Class rbRule : nrbf) {
|
||||
NoRollbackRuleAttribute rule = new NoRollbackRuleAttribute(rbRule);
|
||||
rollBackRules.add(rule);
|
||||
}
|
||||
String[] nrbfc = ann.noRollbackForClassName();
|
||||
String[] nrbfc = attributes.getStringArray("noRollbackForClassName");
|
||||
for (String rbRule : nrbfc) {
|
||||
NoRollbackRuleAttribute rule = new NoRollbackRuleAttribute(rbRule);
|
||||
rollBackRules.add(rule);
|
||||
|
||||
@@ -214,7 +214,7 @@ public class AnnotationTransactionAttributeSourceTests {
|
||||
Method method = TestBean6.class.getMethod("getAge", (Class[]) null);
|
||||
|
||||
AnnotationTransactionAttributeSource atas = new AnnotationTransactionAttributeSource();
|
||||
TransactionAttribute actual = atas.getTransactionAttribute(method, TestBean5.class);
|
||||
TransactionAttribute actual = atas.getTransactionAttribute(method, TestBean6.class);
|
||||
|
||||
RuleBasedTransactionAttribute rbta = new RuleBasedTransactionAttribute();
|
||||
rbta.getRollbackRules().add(new RollbackRuleAttribute(Exception.class));
|
||||
@@ -222,6 +222,36 @@ public class AnnotationTransactionAttributeSourceTests {
|
||||
assertEquals(rbta.getRollbackRules(), ((RuleBasedTransactionAttribute) actual).getRollbackRules());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCustomClassAttributeWithReadOnlyOverrideDetected() throws Exception {
|
||||
Method method = TestBean7.class.getMethod("getAge", (Class[]) null);
|
||||
|
||||
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));
|
||||
assertEquals(rbta.getRollbackRules(), ((RuleBasedTransactionAttribute) actual).getRollbackRules());
|
||||
|
||||
assertTrue(actual.isReadOnly());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCustomMethodAttributeWithReadOnlyOverrideDetected() throws Exception {
|
||||
Method method = TestBean8.class.getMethod("getAge", (Class[]) null);
|
||||
|
||||
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));
|
||||
assertEquals(rbta.getRollbackRules(), ((RuleBasedTransactionAttribute) actual).getRollbackRules());
|
||||
|
||||
assertTrue(actual.isReadOnly());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTransactionAttributeDeclaredOnClassMethodWithEjb3() throws Exception {
|
||||
Method getAgeMethod = ITestBean.class.getMethod("getAge", (Class[]) null);
|
||||
@@ -543,6 +573,33 @@ public class AnnotationTransactionAttributeSourceTests {
|
||||
}
|
||||
|
||||
|
||||
@Target({ElementType.TYPE, ElementType.METHOD})
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Transactional(rollbackFor=Exception.class, noRollbackFor={IOException.class})
|
||||
public @interface TxWithAttribute {
|
||||
|
||||
boolean readOnly();
|
||||
}
|
||||
|
||||
|
||||
@TxWithAttribute(readOnly=true)
|
||||
public static class TestBean7 {
|
||||
|
||||
public int getAge() {
|
||||
return 10;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static class TestBean8 {
|
||||
|
||||
@TxWithAttribute(readOnly=true)
|
||||
public int getAge() {
|
||||
return 10;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static interface Foo<T> {
|
||||
|
||||
void doSomething(T theArgument);
|
||||
|
||||
Reference in New Issue
Block a user