Skip to content

Commit 99733ae

Browse files
committed
introspect superclass when given a CGLIB proxy as target class (SPR-7448); use generic Class<?> in TransactionAttributeSource signature
1 parent 8a23ce9 commit 99733ae

File tree

5 files changed

+42
-20
lines changed

5 files changed

+42
-20
lines changed

org.springframework.transaction/src/main/java/org/springframework/transaction/annotation/AnnotationTransactionAttributeSource.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2009 the original author or authors.
2+
* Copyright 2002-2010 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -114,7 +114,7 @@ protected TransactionAttribute findTransactionAttribute(Method method) {
114114
}
115115

116116
@Override
117-
protected TransactionAttribute findTransactionAttribute(Class clazz) {
117+
protected TransactionAttribute findTransactionAttribute(Class<?> clazz) {
118118
return determineTransactionAttribute(clazz);
119119
}
120120

org.springframework.transaction/src/main/java/org/springframework/transaction/interceptor/AbstractFallbackTransactionAttributeSource.java

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ public abstract class AbstractFallbackTransactionAttributeSource implements Tran
8080
* @return TransactionAttribute for this method, or <code>null</code> if the method
8181
* is not transactional
8282
*/
83-
public TransactionAttribute getTransactionAttribute(Method method, Class targetClass) {
83+
public TransactionAttribute getTransactionAttribute(Method method, Class<?> targetClass) {
8484
// First, see if we have a cached value.
8585
Object cacheKey = getCacheKey(method, targetClass);
8686
Object cached = this.attributeCache.get(cacheKey);
@@ -119,7 +119,7 @@ public TransactionAttribute getTransactionAttribute(Method method, Class targetC
119119
* @param targetClass the target class (may be <code>null</code>)
120120
* @return the cache key (never <code>null</code>)
121121
*/
122-
protected Object getCacheKey(Method method, Class targetClass) {
122+
protected Object getCacheKey(Method method, Class<?> targetClass) {
123123
return new DefaultCacheKey(method, targetClass);
124124
}
125125

@@ -128,15 +128,17 @@ protected Object getCacheKey(Method method, Class targetClass) {
128128
* {@link #getTransactionAttribute} is effectively a caching decorator for this method.
129129
* @see #getTransactionAttribute
130130
*/
131-
private TransactionAttribute computeTransactionAttribute(Method method, Class targetClass) {
131+
private TransactionAttribute computeTransactionAttribute(Method method, Class<?> targetClass) {
132132
// Don't allow no-public methods as required.
133133
if (allowPublicMethodsOnly() && !Modifier.isPublic(method.getModifiers())) {
134134
return null;
135135
}
136136

137+
// Ignore CGLIB subclasses - introspect the actual user class.
138+
Class<?> userClass = ClassUtils.getUserClass(targetClass);
137139
// The method may be on an interface, but we need attributes from the target class.
138140
// If the target class is null, the method will be unchanged.
139-
Method specificMethod = ClassUtils.getMostSpecificMethod(method, targetClass);
141+
Method specificMethod = ClassUtils.getMostSpecificMethod(method, userClass);
140142
// If we are dealing with method with generic parameters, find the original method.
141143
specificMethod = BridgeMethodResolver.findBridgedMethod(specificMethod);
142144

@@ -181,7 +183,7 @@ private TransactionAttribute computeTransactionAttribute(Method method, Class ta
181183
* @return all transaction attribute associated with this class
182184
* (or <code>null</code> if none)
183185
*/
184-
protected abstract TransactionAttribute findTransactionAttribute(Class clazz);
186+
protected abstract TransactionAttribute findTransactionAttribute(Class<?> clazz);
185187

186188

187189
/**

org.springframework.transaction/src/main/java/org/springframework/transaction/interceptor/TransactionAttributeSource.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2006 the original author or authors.
2+
* Copyright 2002-2010 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -39,6 +39,6 @@ public interface TransactionAttributeSource {
3939
* @return TransactionAttribute the matching transaction attribute,
4040
* or <code>null</code> if none found
4141
*/
42-
TransactionAttribute getTransactionAttribute(Method method, Class targetClass);
42+
TransactionAttribute getTransactionAttribute(Method method, Class<?> targetClass);
4343

4444
}

org.springframework.transaction/src/test/java/org/springframework/transaction/annotation/AnnotationTransactionAttributeSourceTests.java

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2006 the original author or authors.
2+
* Copyright 2002-2010 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -95,6 +95,26 @@ public void testTransactionAttributeDeclaredOnClassMethod() throws Exception {
9595
assertEquals(rbta.getRollbackRules(), ((RuleBasedTransactionAttribute) actual).getRollbackRules());
9696
}
9797

98+
/**
99+
* Test the important case where the invocation is on a proxied interface method
100+
* but the attribute is defined on the target class.
101+
*/
102+
@Test
103+
public void testTransactionAttributeDeclaredOnCglibClassMethod() throws Exception {
104+
Method classMethod = ITestBean.class.getMethod("getAge", (Class[]) null);
105+
TestBean1 tb = new TestBean1();
106+
ProxyFactory pf = new ProxyFactory(tb);
107+
pf.setProxyTargetClass(true);
108+
Object proxy = pf.getProxy();
109+
110+
AnnotationTransactionAttributeSource atas = new AnnotationTransactionAttributeSource();
111+
TransactionAttribute actual = atas.getTransactionAttribute(classMethod, proxy.getClass());
112+
113+
RuleBasedTransactionAttribute rbta = new RuleBasedTransactionAttribute();
114+
rbta.getRollbackRules().add(new RollbackRuleAttribute(Exception.class));
115+
assertEquals(rbta.getRollbackRules(), ((RuleBasedTransactionAttribute) actual).getRollbackRules());
116+
}
117+
98118
/**
99119
* Test case where attribute is on the interface method.
100120
*/

org.springframework.transaction/src/test/java/org/springframework/transaction/interceptor/MapTransactionAttributeSource.java

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2007 the original author or authors.
2+
* Copyright 2002-2010 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -27,25 +27,25 @@
2727
* @author Juergen Hoeller
2828
*/
2929
public class MapTransactionAttributeSource extends AbstractFallbackTransactionAttributeSource {
30-
31-
/** Map from Method or Clazz to TransactionAttribute */
32-
private final Map attributeMap = new HashMap();
33-
34-
public void register(Method m, TransactionAttribute txAtt) {
35-
this.attributeMap.put(m, txAtt);
30+
31+
private final Map<Object, TransactionAttribute> attributeMap = new HashMap<Object, TransactionAttribute>();
32+
33+
34+
public void register(Method method, TransactionAttribute txAtt) {
35+
this.attributeMap.put(method, txAtt);
3636
}
37-
37+
3838
public void register(Class clazz, TransactionAttribute txAtt) {
3939
this.attributeMap.put(clazz, txAtt);
4040
}
4141

4242

4343
protected TransactionAttribute findTransactionAttribute(Method method) {
44-
return (TransactionAttribute) this.attributeMap.get(method);
44+
return this.attributeMap.get(method);
4545
}
4646

4747
protected TransactionAttribute findTransactionAttribute(Class clazz) {
48-
return (TransactionAttribute) this.attributeMap.get(clazz);
48+
return this.attributeMap.get(clazz);
4949
}
5050

5151
}

0 commit comments

Comments
 (0)