Skip to content

Commit 416dee7

Browse files
committed
AspectJExpressionPointcut evaluates interface method on proxy as well
Issue: SPR-16803 (cherry picked from commit bba5dca)
1 parent 4d69ec4 commit 416dee7

File tree

2 files changed

+53
-12
lines changed

2 files changed

+53
-12
lines changed

spring-aop/src/main/java/org/springframework/aop/aspectj/AspectJExpressionPointcut.java

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
import java.io.IOException;
2020
import java.io.ObjectInputStream;
2121
import java.lang.reflect.Method;
22+
import java.lang.reflect.Proxy;
2223
import java.util.Arrays;
2324
import java.util.HashSet;
2425
import java.util.Map;
@@ -428,6 +429,9 @@ private void bindParameters(ProxyMethodInvocation invocation, JoinPointMatch jpm
428429
private ShadowMatch getTargetShadowMatch(Method method, @Nullable Class<?> targetClass) {
429430
Method targetMethod = AopUtils.getMostSpecificMethod(method, targetClass);
430431
if (targetClass != null && targetMethod.getDeclaringClass().isInterface()) {
432+
// Try to build the most specific interface possible for inherited methods to be
433+
// considered for sub-interface matches as well, in particular for proxy classes.
434+
// Note: AspectJ is only going to take Method.getDeclaringClass() into account.
431435
Set<Class<?>> ifcs = ClassUtils.getAllInterfacesForClassAsSet(targetClass);
432436
if (ifcs.size() > 1) {
433437
Class<?> compositeInterface = ClassUtils.createCompositeInterface(
@@ -465,7 +469,11 @@ private ShadowMatch getShadowMatch(Method targetMethod, Method originalMethod) {
465469
fallbackExpression = null;
466470
}
467471
}
468-
if (shadowMatch == null && targetMethod != originalMethod) {
472+
if (targetMethod != originalMethod && (shadowMatch == null ||
473+
(shadowMatch.neverMatches() && Proxy.isProxyClass(targetMethod.getDeclaringClass())))) {
474+
// Fall back to the plain original method in case of no resolvable match or a
475+
// negative match on a proxy class (which doesn't carry any annotations on its
476+
// redeclared methods).
469477
methodToMatch = originalMethod;
470478
try {
471479
shadowMatch = obtainPointcutExpression().matchesMethodExecution(methodToMatch);

spring-aop/src/test/java/org/springframework/aop/aspectj/TigerAspectJExpressionPointcutTests.java

Lines changed: 44 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
import test.annotation.EmptySpringAnnotation;
2727
import test.annotation.transaction.Tx;
2828

29+
import org.springframework.aop.framework.ProxyFactory;
2930
import org.springframework.tests.sample.beans.TestBean;
3031

3132
import static org.junit.Assert.*;
@@ -73,7 +74,7 @@ public void testMatchGenericArgument() {
7374
}
7475

7576
@Test
76-
public void testMatchVarargs() throws SecurityException, NoSuchMethodException {
77+
public void testMatchVarargs() throws Exception {
7778

7879
@SuppressWarnings("unused")
7980
class MyTemplate {
@@ -99,19 +100,19 @@ public int queryForInt(String sql, Object... params) {
99100
}
100101

101102
@Test
102-
public void testMatchAnnotationOnClassWithAtWithin() throws SecurityException, NoSuchMethodException {
103+
public void testMatchAnnotationOnClassWithAtWithin() throws Exception {
103104
String expression = "@within(test.annotation.transaction.Tx)";
104105
testMatchAnnotationOnClass(expression);
105106
}
106107

107108
@Test
108-
public void testMatchAnnotationOnClassWithoutBinding() throws SecurityException, NoSuchMethodException {
109+
public void testMatchAnnotationOnClassWithoutBinding() throws Exception {
109110
String expression = "within(@test.annotation.transaction.Tx *)";
110111
testMatchAnnotationOnClass(expression);
111112
}
112113

113114
@Test
114-
public void testMatchAnnotationOnClassWithSubpackageWildcard() throws SecurityException, NoSuchMethodException {
115+
public void testMatchAnnotationOnClassWithSubpackageWildcard() throws Exception {
115116
String expression = "within(@(test.annotation..*) *)";
116117
AspectJExpressionPointcut springAnnotatedPc = testMatchAnnotationOnClass(expression);
117118
assertFalse(springAnnotatedPc.matches(TestBean.class.getMethod("setName", String.class), TestBean.class));
@@ -123,12 +124,12 @@ public void testMatchAnnotationOnClassWithSubpackageWildcard() throws SecurityEx
123124
}
124125

125126
@Test
126-
public void testMatchAnnotationOnClassWithExactPackageWildcard() throws SecurityException, NoSuchMethodException {
127+
public void testMatchAnnotationOnClassWithExactPackageWildcard() throws Exception {
127128
String expression = "within(@(test.annotation.transaction.*) *)";
128129
testMatchAnnotationOnClass(expression);
129130
}
130131

131-
private AspectJExpressionPointcut testMatchAnnotationOnClass(String expression) throws SecurityException, NoSuchMethodException {
132+
private AspectJExpressionPointcut testMatchAnnotationOnClass(String expression) throws Exception {
132133
AspectJExpressionPointcut ajexp = new AspectJExpressionPointcut();
133134
ajexp.setExpression(expression);
134135

@@ -141,7 +142,7 @@ private AspectJExpressionPointcut testMatchAnnotationOnClass(String expression)
141142
}
142143

143144
@Test
144-
public void testAnnotationOnMethodWithFQN() throws SecurityException, NoSuchMethodException {
145+
public void testAnnotationOnMethodWithFQN() throws Exception {
145146
String expression = "@annotation(test.annotation.transaction.Tx)";
146147
AspectJExpressionPointcut ajexp = new AspectJExpressionPointcut();
147148
ajexp.setExpression(expression);
@@ -155,7 +156,31 @@ public void testAnnotationOnMethodWithFQN() throws SecurityException, NoSuchMeth
155156
}
156157

157158
@Test
158-
public void testAnnotationOnMethodWithWildcard() throws SecurityException, NoSuchMethodException {
159+
public void testAnnotationOnCglibProxyMethod() throws Exception {
160+
String expression = "@annotation(test.annotation.transaction.Tx)";
161+
AspectJExpressionPointcut ajexp = new AspectJExpressionPointcut();
162+
ajexp.setExpression(expression);
163+
164+
ProxyFactory factory = new ProxyFactory(new BeanA());
165+
factory.setProxyTargetClass(true);
166+
BeanA proxy = (BeanA) factory.getProxy();
167+
assertTrue(ajexp.matches(BeanA.class.getMethod("getAge"), proxy.getClass()));
168+
}
169+
170+
@Test
171+
public void testAnnotationOnDynamicProxyMethod() throws Exception {
172+
String expression = "@annotation(test.annotation.transaction.Tx)";
173+
AspectJExpressionPointcut ajexp = new AspectJExpressionPointcut();
174+
ajexp.setExpression(expression);
175+
176+
ProxyFactory factory = new ProxyFactory(new BeanA());
177+
factory.setProxyTargetClass(false);
178+
IBeanA proxy = (IBeanA) factory.getProxy();
179+
assertTrue(ajexp.matches(IBeanA.class.getMethod("getAge"), proxy.getClass()));
180+
}
181+
182+
@Test
183+
public void testAnnotationOnMethodWithWildcard() throws Exception {
159184
String expression = "execution(@(test.annotation..*) * *(..))";
160185
AspectJExpressionPointcut anySpringMethodAnnotation = new AspectJExpressionPointcut();
161186
anySpringMethodAnnotation.setExpression(expression);
@@ -171,7 +196,7 @@ public void testAnnotationOnMethodWithWildcard() throws SecurityException, NoSuc
171196
}
172197

173198
@Test
174-
public void testAnnotationOnMethodArgumentsWithFQN() throws SecurityException, NoSuchMethodException {
199+
public void testAnnotationOnMethodArgumentsWithFQN() throws Exception {
175200
String expression = "@args(*, test.annotation.EmptySpringAnnotation))";
176201
AspectJExpressionPointcut takesSpringAnnotatedArgument2 = new AspectJExpressionPointcut();
177202
takesSpringAnnotatedArgument2.setExpression(expression);
@@ -201,7 +226,7 @@ ProcessesSpringAnnotatedParameters.class, new TestBean(), new BeanA())
201226
}
202227

203228
@Test
204-
public void testAnnotationOnMethodArgumentsWithWildcards() throws SecurityException, NoSuchMethodException {
229+
public void testAnnotationOnMethodArgumentsWithWildcards() throws Exception {
205230
String expression = "execution(* *(*, @(test..*) *))";
206231
AspectJExpressionPointcut takesSpringAnnotatedArgument2 = new AspectJExpressionPointcut();
207232
takesSpringAnnotatedArgument2.setExpression(expression);
@@ -266,7 +291,14 @@ public void foo() {
266291
}
267292

268293

269-
static class BeanA {
294+
interface IBeanA {
295+
296+
@Tx
297+
int getAge();
298+
}
299+
300+
301+
static class BeanA implements IBeanA {
270302

271303
private String name;
272304

@@ -277,6 +309,7 @@ public void setName(String name) {
277309
}
278310

279311
@Tx
312+
@Override
280313
public int getAge() {
281314
return age;
282315
}

0 commit comments

Comments
 (0)