Browse Source

AnnotationTransactionAttributeSource applies class-level metadata to user-level methods only

Issue: SPR-14095
pull/1019/merge
Juergen Hoeller 9 years ago
parent
commit
b7819e6ec8
  1. 1
      build.gradle
  2. 8
      spring-tx/src/main/java/org/springframework/transaction/interceptor/AbstractFallbackTransactionAttributeSource.java
  3. 94
      spring-tx/src/test/java/org/springframework/transaction/annotation/AnnotationTransactionAttributeSourceTests.java

1
build.gradle

@ -556,6 +556,7 @@ project("spring-tx") { @@ -556,6 +556,7 @@ project("spring-tx") {
optional("com.ibm.websphere:uow:6.0.2.17")
testCompile("org.aspectj:aspectjweaver:${aspectjVersion}")
testCompile("org.eclipse.persistence:javax.persistence:2.0.0")
testCompile("org.codehaus.groovy:groovy-all:${groovyVersion}")
}
}

8
spring-tx/src/main/java/org/springframework/transaction/interceptor/AbstractFallbackTransactionAttributeSource.java

@ -155,7 +155,7 @@ public abstract class AbstractFallbackTransactionAttributeSource implements Tran @@ -155,7 +155,7 @@ public abstract class AbstractFallbackTransactionAttributeSource implements Tran
// Second try is the transaction attribute on the target class.
txAtt = findTransactionAttribute(specificMethod.getDeclaringClass());
if (txAtt != null) {
if (txAtt != null && ClassUtils.isUserLevelMethod(method)) {
return txAtt;
}
@ -166,8 +166,12 @@ public abstract class AbstractFallbackTransactionAttributeSource implements Tran @@ -166,8 +166,12 @@ public abstract class AbstractFallbackTransactionAttributeSource implements Tran
return txAtt;
}
// Last fallback is the class of the original method.
return findTransactionAttribute(method.getDeclaringClass());
txAtt = findTransactionAttribute(method.getDeclaringClass());
if (txAtt != null && ClassUtils.isUserLevelMethod(method)) {
return txAtt;
}
}
return null;
}

94
spring-tx/src/test/java/org/springframework/transaction/annotation/AnnotationTransactionAttributeSourceTests.java

@ -1,5 +1,5 @@ @@ -1,5 +1,5 @@
/*
* Copyright 2002-2015 the original author or authors.
* Copyright 2002-2016 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,9 +21,10 @@ import java.io.Serializable; @@ -21,9 +21,10 @@ import java.io.Serializable;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.reflect.Method;
import javax.ejb.TransactionAttributeType;
import groovy.lang.GroovyObject;
import groovy.lang.MetaClass;
import org.junit.Test;
import org.springframework.aop.framework.Advised;
@ -54,7 +55,7 @@ public class AnnotationTransactionAttributeSourceTests { @@ -54,7 +55,7 @@ public class AnnotationTransactionAttributeSourceTests {
TransactionInterceptor ti = new TransactionInterceptor(ptm, tas);
ProxyFactory proxyFactory = new ProxyFactory();
proxyFactory.setInterfaces(new Class[] {ITestBean.class});
proxyFactory.setInterfaces(ITestBean.class);
proxyFactory.addAdvice(ti);
proxyFactory.setTarget(tb);
ITestBean proxy = (ITestBean) proxyFactory.getProxy();
@ -369,6 +370,20 @@ public class AnnotationTransactionAttributeSourceTests { @@ -369,6 +370,20 @@ public class AnnotationTransactionAttributeSourceTests {
assertEquals(TransactionAttribute.PROPAGATION_SUPPORTS, getNameAttr.getPropagationBehavior());
}
@Test
public void transactionAttributeDeclaredOnGroovyClass() throws Exception {
Method getAgeMethod = ITestBean.class.getMethod("getAge");
Method getNameMethod = ITestBean.class.getMethod("getName");
Method getMetaClassMethod = GroovyObject.class.getMethod("getMetaClass");
AnnotationTransactionAttributeSource atas = new AnnotationTransactionAttributeSource();
TransactionAttribute getAgeAttr = atas.getTransactionAttribute(getAgeMethod, GroovyTestBean.class);
assertEquals(TransactionAttribute.PROPAGATION_REQUIRED, getAgeAttr.getPropagationBehavior());
TransactionAttribute getNameAttr = atas.getTransactionAttribute(getNameMethod, GroovyTestBean.class);
assertEquals(TransactionAttribute.PROPAGATION_REQUIRED, getNameAttr.getPropagationBehavior());
assertNull(atas.getTransactionAttribute(getMetaClassMethod, GroovyTestBean.class));
}
interface ITestBean {
@ -470,7 +485,7 @@ public class AnnotationTransactionAttributeSourceTests { @@ -470,7 +485,7 @@ public class AnnotationTransactionAttributeSourceTests {
}
@Override
@Transactional(rollbackFor=Exception.class)
@Transactional(rollbackFor = Exception.class)
public int getAge() {
return age;
}
@ -543,8 +558,8 @@ public class AnnotationTransactionAttributeSourceTests { @@ -543,8 +558,8 @@ public class AnnotationTransactionAttributeSourceTests {
}
@Override
@Transactional(propagation=Propagation.REQUIRES_NEW, isolation=Isolation.REPEATABLE_READ, timeout=5,
readOnly=true, rollbackFor=Exception.class, noRollbackFor={IOException.class})
@Transactional(propagation = Propagation.REQUIRES_NEW, isolation=Isolation.REPEATABLE_READ,
timeout = 5, readOnly = true, rollbackFor = Exception.class, noRollbackFor = IOException.class)
public int getAge() {
return age;
}
@ -556,7 +571,7 @@ public class AnnotationTransactionAttributeSourceTests { @@ -556,7 +571,7 @@ public class AnnotationTransactionAttributeSourceTests {
}
@Transactional(rollbackFor=Exception.class, noRollbackFor={IOException.class})
@Transactional(rollbackFor = Exception.class, noRollbackFor = IOException.class)
static class TestBean4 implements ITestBean3 {
private String name;
@ -594,7 +609,7 @@ public class AnnotationTransactionAttributeSourceTests { @@ -594,7 +609,7 @@ public class AnnotationTransactionAttributeSourceTests {
@Retention(RetentionPolicy.RUNTIME)
@Transactional(rollbackFor=Exception.class, noRollbackFor={IOException.class})
@Transactional(rollbackFor = Exception.class, noRollbackFor = IOException.class)
@interface Tx {
}
@ -618,13 +633,13 @@ public class AnnotationTransactionAttributeSourceTests { @@ -618,13 +633,13 @@ public class AnnotationTransactionAttributeSourceTests {
@Retention(RetentionPolicy.RUNTIME)
@Transactional(rollbackFor=Exception.class, noRollbackFor={IOException.class})
@Transactional(rollbackFor = Exception.class, noRollbackFor = IOException.class)
@interface TxWithAttribute {
boolean readOnly();
}
@TxWithAttribute(readOnly=true)
@TxWithAttribute(readOnly = true)
static class TestBean7 {
public int getAge() {
@ -641,11 +656,14 @@ public class AnnotationTransactionAttributeSourceTests { @@ -641,11 +656,14 @@ public class AnnotationTransactionAttributeSourceTests {
}
}
@TxWithAttribute(readOnly = true)
interface TestInterface9 {
int getAge();
}
static class TestBean9 implements TestInterface9 {
@Override
@ -654,12 +672,14 @@ public class AnnotationTransactionAttributeSourceTests { @@ -654,12 +672,14 @@ public class AnnotationTransactionAttributeSourceTests {
}
}
interface TestInterface10 {
@TxWithAttribute(readOnly=true)
@TxWithAttribute(readOnly = true)
int getAge();
}
static class TestBean10 implements TestInterface10 {
@Override
@ -888,4 +908,56 @@ public class AnnotationTransactionAttributeSourceTests { @@ -888,4 +908,56 @@ public class AnnotationTransactionAttributeSourceTests {
}
}
@Transactional
static class GroovyTestBean implements ITestBean, 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) {
}
}
}

Loading…
Cancel
Save