1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.springframework.aop.aspectj;
18
19 import java.lang.reflect.Field;
20
21 import org.aspectj.weaver.ReferenceType;
22 import org.aspectj.weaver.ReferenceTypeDelegate;
23 import org.aspectj.weaver.ResolvedType;
24 import org.aspectj.weaver.ast.And;
25 import org.aspectj.weaver.ast.Call;
26 import org.aspectj.weaver.ast.FieldGetCall;
27 import org.aspectj.weaver.ast.HasAnnotation;
28 import org.aspectj.weaver.ast.ITestVisitor;
29 import org.aspectj.weaver.ast.Instanceof;
30 import org.aspectj.weaver.ast.Literal;
31 import org.aspectj.weaver.ast.Not;
32 import org.aspectj.weaver.ast.Or;
33 import org.aspectj.weaver.ast.Test;
34 import org.aspectj.weaver.internal.tools.MatchingContextBasedTest;
35 import org.aspectj.weaver.reflect.ReflectionBasedReferenceTypeDelegate;
36 import org.aspectj.weaver.reflect.ReflectionVar;
37 import org.aspectj.weaver.reflect.ShadowMatchImpl;
38 import org.aspectj.weaver.tools.ShadowMatch;
39
40 import org.springframework.util.ClassUtils;
41 import org.springframework.util.ReflectionUtils;
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59 class RuntimeTestWalker {
60
61 private static final Field residualTestField;
62
63 private static final Field varTypeField;
64
65 private static final Field myClassField;
66
67
68 static {
69 try {
70 residualTestField = ShadowMatchImpl.class.getDeclaredField("residualTest");
71 varTypeField = ReflectionVar.class.getDeclaredField("varType");
72 myClassField = ReflectionBasedReferenceTypeDelegate.class.getDeclaredField("myClass");
73 }
74 catch (NoSuchFieldException ex) {
75 throw new IllegalStateException("The version of aspectjtools.jar / aspectjweaver.jar " +
76 "on the classpath is incompatible with this version of Spring: " + ex);
77 }
78 }
79
80
81 private final Test runtimeTest;
82
83
84 public RuntimeTestWalker(ShadowMatch shadowMatch) {
85 try {
86 ReflectionUtils.makeAccessible(residualTestField);
87 this.runtimeTest = (Test) residualTestField.get(shadowMatch);
88 }
89 catch (IllegalAccessException ex) {
90 throw new IllegalStateException(ex);
91 }
92 }
93
94
95
96
97
98
99 public boolean testsSubtypeSensitiveVars() {
100 return (this.runtimeTest != null &&
101 new SubtypeSensitiveVarTypeTestVisitor().testsSubtypeSensitiveVars(this.runtimeTest));
102 }
103
104 public boolean testThisInstanceOfResidue(Class<?> thisClass) {
105 return (this.runtimeTest != null &&
106 new ThisInstanceOfResidueTestVisitor(thisClass).thisInstanceOfMatches(this.runtimeTest));
107 }
108
109 public boolean testTargetInstanceOfResidue(Class<?> targetClass) {
110 return (this.runtimeTest != null &&
111 new TargetInstanceOfResidueTestVisitor(targetClass).targetInstanceOfMatches(this.runtimeTest));
112 }
113
114
115 private static class TestVisitorAdapter implements ITestVisitor {
116
117 protected static final int THIS_VAR = 0;
118 protected static final int TARGET_VAR = 1;
119 protected static final int AT_THIS_VAR = 3;
120 protected static final int AT_TARGET_VAR = 4;
121 protected static final int AT_ANNOTATION_VAR = 8;
122
123 @Override
124 public void visit(And e) {
125 e.getLeft().accept(this);
126 e.getRight().accept(this);
127 }
128
129 @Override
130 public void visit(Or e) {
131 e.getLeft().accept(this);
132 e.getRight().accept(this);
133 }
134
135 @Override
136 public void visit(Not e) {
137 e.getBody().accept(this);
138 }
139
140 @Override
141 public void visit(Instanceof i) {
142 }
143
144 @Override
145 public void visit(Literal literal) {
146 }
147
148 @Override
149 public void visit(Call call) {
150 }
151
152 @Override
153 public void visit(FieldGetCall fieldGetCall) {
154 }
155
156 @Override
157 public void visit(HasAnnotation hasAnnotation) {
158 }
159
160 @Override
161 public void visit(MatchingContextBasedTest matchingContextTest) {
162 }
163
164 protected int getVarType(ReflectionVar v) {
165 try {
166 ReflectionUtils.makeAccessible(varTypeField);
167 return (Integer) varTypeField.get(v);
168 }
169 catch (IllegalAccessException ex) {
170 throw new IllegalStateException(ex);
171 }
172 }
173 }
174
175
176 private static abstract class InstanceOfResidueTestVisitor extends TestVisitorAdapter {
177
178 private final Class<?> matchClass;
179
180 private boolean matches;
181
182 private final int matchVarType;
183
184 public InstanceOfResidueTestVisitor(Class<?> matchClass, boolean defaultMatches, int matchVarType) {
185 this.matchClass = matchClass;
186 this.matches = defaultMatches;
187 this.matchVarType = matchVarType;
188 }
189
190 public boolean instanceOfMatches(Test test) {
191 test.accept(this);
192 return this.matches;
193 }
194
195 @Override
196 public void visit(Instanceof i) {
197 int varType = getVarType((ReflectionVar) i.getVar());
198 if (varType != this.matchVarType) {
199 return;
200 }
201 Class<?> typeClass = null;
202 ResolvedType type = (ResolvedType) i.getType();
203 if (type instanceof ReferenceType) {
204 ReferenceTypeDelegate delegate = ((ReferenceType) type).getDelegate();
205 if (delegate instanceof ReflectionBasedReferenceTypeDelegate) {
206 try {
207 ReflectionUtils.makeAccessible(myClassField);
208 typeClass = (Class<?>) myClassField.get(delegate);
209 }
210 catch (IllegalAccessException ex) {
211 throw new IllegalStateException(ex);
212 }
213 }
214 }
215 try {
216
217 if (typeClass == null) {
218 typeClass = ClassUtils.forName(type.getName(), this.matchClass.getClassLoader());
219 }
220 this.matches = typeClass.isAssignableFrom(this.matchClass);
221 }
222 catch (ClassNotFoundException ex) {
223 this.matches = false;
224 }
225 }
226 }
227
228
229
230
231
232 private static class TargetInstanceOfResidueTestVisitor extends InstanceOfResidueTestVisitor {
233
234 public TargetInstanceOfResidueTestVisitor(Class<?> targetClass) {
235 super(targetClass, false, TARGET_VAR);
236 }
237
238 public boolean targetInstanceOfMatches(Test test) {
239 return instanceOfMatches(test);
240 }
241 }
242
243
244
245
246
247 private static class ThisInstanceOfResidueTestVisitor extends InstanceOfResidueTestVisitor {
248
249 public ThisInstanceOfResidueTestVisitor(Class<?> thisClass) {
250 super(thisClass, true, THIS_VAR);
251 }
252
253
254 public boolean thisInstanceOfMatches(Test test) {
255 return instanceOfMatches(test);
256 }
257 }
258
259
260 private static class SubtypeSensitiveVarTypeTestVisitor extends TestVisitorAdapter {
261
262 private final Object thisObj = new Object();
263
264 private final Object targetObj = new Object();
265
266 private final Object[] argsObjs = new Object[0];
267
268 private boolean testsSubtypeSensitiveVars = false;
269
270 public boolean testsSubtypeSensitiveVars(Test aTest) {
271 aTest.accept(this);
272 return this.testsSubtypeSensitiveVars;
273 }
274
275 @Override
276 public void visit(Instanceof i) {
277 ReflectionVar v = (ReflectionVar) i.getVar();
278 Object varUnderTest = v.getBindingAtJoinPoint(this.thisObj, this.targetObj, this.argsObjs);
279 if (varUnderTest == this.thisObj || varUnderTest == this.targetObj) {
280 this.testsSubtypeSensitiveVars = true;
281 }
282 }
283
284 @Override
285 public void visit(HasAnnotation hasAnn) {
286
287 ReflectionVar v = (ReflectionVar) hasAnn.getVar();
288 int varType = getVarType(v);
289 if (varType == AT_THIS_VAR || varType == AT_TARGET_VAR || varType == AT_ANNOTATION_VAR) {
290 this.testsSubtypeSensitiveVars = true;
291 }
292 }
293 }
294
295 }