1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.springframework.aop.framework;
18
19 import java.io.Serializable;
20
21 import org.aopalliance.intercept.MethodInterceptor;
22 import org.aopalliance.intercept.MethodInvocation;
23 import org.junit.Test;
24 import test.mixin.LockMixinAdvisor;
25
26 import org.springframework.aop.ClassFilter;
27 import org.springframework.aop.MethodMatcher;
28 import org.springframework.aop.Pointcut;
29 import org.springframework.aop.support.AopUtils;
30 import org.springframework.aop.support.DefaultPointcutAdvisor;
31 import org.springframework.context.ApplicationContext;
32 import org.springframework.context.ApplicationContextException;
33 import org.springframework.context.support.ClassPathXmlApplicationContext;
34 import org.springframework.tests.aop.advice.CountingBeforeAdvice;
35 import org.springframework.tests.aop.interceptor.NopInterceptor;
36 import org.springframework.tests.sample.beans.ITestBean;
37 import org.springframework.tests.sample.beans.TestBean;
38
39 import static org.hamcrest.CoreMatchers.*;
40 import static org.junit.Assert.*;
41
42
43
44
45
46
47
48
49
50
51 @SuppressWarnings("serial")
52 public final class CglibProxyTests extends AbstractAopProxyTests implements Serializable {
53
54 private static final String DEPENDENCY_CHECK_CONTEXT =
55 CglibProxyTests.class.getSimpleName() + "-with-dependency-checking.xml";
56
57
58 @Override
59 protected Object createProxy(ProxyCreatorSupport as) {
60 as.setProxyTargetClass(true);
61 Object proxy = as.createAopProxy().getProxy();
62 assertTrue(AopUtils.isCglibProxy(proxy));
63 return proxy;
64 }
65
66 @Override
67 protected AopProxy createAopProxy(AdvisedSupport as) {
68 as.setProxyTargetClass(true);
69 return new CglibAopProxy(as);
70 }
71
72 @Override
73 protected boolean requiresTarget() {
74 return true;
75 }
76
77 @Test
78 public void testNullConfig() {
79 try {
80 new CglibAopProxy(null);
81 fail("Shouldn't allow null interceptors");
82 }
83 catch (IllegalArgumentException ex) {
84
85 }
86 }
87
88 @Test
89 public void testNoTarget() {
90 AdvisedSupport pc = new AdvisedSupport(new Class<?>[]{ITestBean.class});
91 pc.addAdvice(new NopInterceptor());
92 try {
93 AopProxy aop = createAopProxy(pc);
94 aop.getProxy();
95 fail("Shouldn't allow no target with CGLIB proxy");
96 }
97 catch (AopConfigException ex) {
98
99 }
100 }
101
102 @Test
103 public void testProtectedMethodInvocation() {
104 ProtectedMethodTestBean bean = new ProtectedMethodTestBean();
105 bean.value = "foo";
106 mockTargetSource.setTarget(bean);
107
108 AdvisedSupport as = new AdvisedSupport(new Class<?>[]{});
109 as.setTargetSource(mockTargetSource);
110 as.addAdvice(new NopInterceptor());
111 AopProxy aop = new CglibAopProxy(as);
112
113 ProtectedMethodTestBean proxy = (ProtectedMethodTestBean) aop.getProxy();
114 assertTrue(AopUtils.isCglibProxy(proxy));
115 assertEquals(proxy.getClass().getClassLoader(), bean.getClass().getClassLoader());
116 assertEquals("foo", proxy.getString());
117 }
118
119 @Test
120 public void testPackageMethodInvocation() {
121 PackageMethodTestBean bean = new PackageMethodTestBean();
122 bean.value = "foo";
123 mockTargetSource.setTarget(bean);
124
125 AdvisedSupport as = new AdvisedSupport(new Class<?>[]{});
126 as.setTargetSource(mockTargetSource);
127 as.addAdvice(new NopInterceptor());
128 AopProxy aop = new CglibAopProxy(as);
129
130 PackageMethodTestBean proxy = (PackageMethodTestBean) aop.getProxy();
131 assertTrue(AopUtils.isCglibProxy(proxy));
132 assertEquals(proxy.getClass().getClassLoader(), bean.getClass().getClassLoader());
133 assertEquals("foo", proxy.getString());
134 }
135
136 @Test
137 public void testPackageMethodInvocationWithDifferentClassLoader() {
138 ClassLoader child = new ClassLoader(getClass().getClassLoader()) {
139 };
140
141 PackageMethodTestBean bean = new PackageMethodTestBean();
142 bean.value = "foo";
143 mockTargetSource.setTarget(bean);
144
145 AdvisedSupport as = new AdvisedSupport(new Class<?>[]{});
146 as.setTargetSource(mockTargetSource);
147 as.addAdvice(new NopInterceptor());
148 AopProxy aop = new CglibAopProxy(as);
149
150 PackageMethodTestBean proxy = (PackageMethodTestBean) aop.getProxy(child);
151 assertTrue(AopUtils.isCglibProxy(proxy));
152 assertNotEquals(proxy.getClass().getClassLoader(), bean.getClass().getClassLoader());
153 assertNull(proxy.getString());
154 }
155
156 @Test
157 public void testProxyCanBeClassNotInterface() throws Exception {
158 TestBean raw = new TestBean();
159 raw.setAge(32);
160 mockTargetSource.setTarget(raw);
161 AdvisedSupport pc = new AdvisedSupport();
162 pc.setTargetSource(mockTargetSource);
163 AopProxy aop = new CglibAopProxy(pc);
164
165 Object proxy = aop.getProxy();
166 assertTrue(AopUtils.isCglibProxy(proxy));
167 assertTrue(proxy instanceof ITestBean);
168 assertTrue(proxy instanceof TestBean);
169
170 TestBean tb = (TestBean) proxy;
171 assertEquals(32, tb.getAge());
172 }
173
174 @Test
175 public void testMethodInvocationDuringConstructor() {
176 CglibTestBean bean = new CglibTestBean();
177 bean.setName("Rob Harrop");
178
179 AdvisedSupport as = new AdvisedSupport(new Class<?>[]{});
180 as.setTarget(bean);
181 as.addAdvice(new NopInterceptor());
182 AopProxy aop = new CglibAopProxy(as);
183
184 CglibTestBean proxy = (CglibTestBean) aop.getProxy();
185 assertEquals("The name property has been overwritten by the constructor", "Rob Harrop", proxy.getName());
186 }
187
188 @Test
189 public void testUnadvisedProxyCreationWithCallDuringConstructor() throws Exception {
190 CglibTestBean target = new CglibTestBean();
191 target.setName("Rob Harrop");
192
193 AdvisedSupport pc = new AdvisedSupport(new Class<?>[]{});
194 pc.setFrozen(true);
195 pc.setTarget(target);
196
197 CglibAopProxy aop = new CglibAopProxy(pc);
198 CglibTestBean proxy = (CglibTestBean) aop.getProxy();
199 assertNotNull("Proxy should not be null", proxy);
200 assertEquals("Constructor overrode the value of name", "Rob Harrop", proxy.getName());
201 }
202
203 @Test
204 public void testMultipleProxies() {
205 TestBean target = new TestBean();
206 target.setAge(20);
207 TestBean target2 = new TestBean();
208 target2.setAge(21);
209
210 ITestBean proxy1 = getAdvisedProxy(target);
211 ITestBean proxy2 = getAdvisedProxy(target2);
212 assertTrue(proxy1.getClass() == proxy2.getClass());
213 assertEquals(target.getAge(), proxy1.getAge());
214 assertEquals(target2.getAge(), proxy2.getAge());
215 }
216
217 private ITestBean getAdvisedProxy(TestBean target) {
218 ProxyFactory pf = new ProxyFactory(new Class<?>[]{ITestBean.class});
219 pf.setProxyTargetClass(true);
220
221 MethodInterceptor advice = new NopInterceptor();
222 Pointcut pointcut = new Pointcut() {
223 @Override
224 public ClassFilter getClassFilter() {
225 return ClassFilter.TRUE;
226 }
227 @Override
228 public MethodMatcher getMethodMatcher() {
229 return MethodMatcher.TRUE;
230 }
231 @Override
232 public boolean equals(Object obj) {
233 return true;
234 }
235 @Override
236 public int hashCode() {
237 return 0;
238 }
239 };
240 pf.addAdvisor(new DefaultPointcutAdvisor(pointcut, advice));
241
242 pf.setTarget(target);
243 pf.setFrozen(true);
244 pf.setExposeProxy(false);
245
246 return (ITestBean) pf.getProxy();
247 }
248
249 @Test
250 public void testMultipleProxiesForIntroductionAdvisor() {
251 TestBean target = new TestBean();
252 target.setAge(20);
253 TestBean target2 = new TestBean();
254 target2.setAge(21);
255
256 ITestBean proxy1 = getIntroductionAdvisorProxy(target);
257 ITestBean proxy2 = getIntroductionAdvisorProxy(target2);
258 assertTrue("Incorrect duplicate creation of proxy classes", proxy1.getClass() == proxy2.getClass());
259 }
260
261 private ITestBean getIntroductionAdvisorProxy(TestBean target) {
262 ProxyFactory pf = new ProxyFactory(new Class<?>[] {ITestBean.class});
263 pf.setProxyTargetClass(true);
264
265 pf.addAdvisor(new LockMixinAdvisor());
266 pf.setTarget(target);
267 pf.setFrozen(true);
268 pf.setExposeProxy(false);
269
270 return (ITestBean) pf.getProxy();
271 }
272
273 @Test
274 public void testWithNoArgConstructor() {
275 NoArgCtorTestBean target = new NoArgCtorTestBean("b", 1);
276 target.reset();
277
278 mockTargetSource.setTarget(target);
279 AdvisedSupport pc = new AdvisedSupport(new Class<?>[]{});
280 pc.setTargetSource(mockTargetSource);
281 CglibAopProxy aop = new CglibAopProxy(pc);
282 aop.setConstructorArguments(new Object[] {"Rob Harrop", 22}, new Class<?>[] {String.class, int.class});
283
284 NoArgCtorTestBean proxy = (NoArgCtorTestBean) aop.getProxy();
285 proxy = (NoArgCtorTestBean) aop.getProxy();
286
287 assertNotNull("Proxy should be null", proxy);
288 }
289
290 @Test
291 public void testProxyAProxy() {
292 ITestBean target = new TestBean();
293
294 mockTargetSource.setTarget(target);
295 AdvisedSupport as = new AdvisedSupport(new Class<?>[]{});
296 as.setTargetSource(mockTargetSource);
297 as.addAdvice(new NopInterceptor());
298 CglibAopProxy cglib = new CglibAopProxy(as);
299
300 ITestBean proxy1 = (ITestBean) cglib.getProxy();
301
302 mockTargetSource.setTarget(proxy1);
303 as = new AdvisedSupport(new Class<?>[]{});
304 as.setTargetSource(mockTargetSource);
305 as.addAdvice(new NopInterceptor());
306 cglib = new CglibAopProxy(as);
307
308 assertThat(cglib.getProxy(), instanceOf(ITestBean.class));
309 }
310
311 @Test
312 public void testProxyAProxyWithAdditionalInterface() {
313 ITestBean target = new TestBean();
314 mockTargetSource.setTarget(target);
315
316 AdvisedSupport as = new AdvisedSupport(new Class<?>[]{});
317 as.setTargetSource(mockTargetSource);
318 as.addAdvice(new NopInterceptor());
319 as.addInterface(Serializable.class);
320 CglibAopProxy cglib = new CglibAopProxy(as);
321
322 ITestBean proxy1 = (ITestBean) cglib.getProxy();
323
324 mockTargetSource.setTarget(proxy1);
325 as = new AdvisedSupport(new Class<?>[]{});
326 as.setTargetSource(mockTargetSource);
327 as.addAdvice(new NopInterceptor());
328 cglib = new CglibAopProxy(as);
329
330 ITestBean proxy2 = (ITestBean) cglib.getProxy();
331 assertTrue(proxy2 instanceof Serializable);
332 }
333
334 @Test
335 public void testExceptionHandling() {
336 ExceptionThrower bean = new ExceptionThrower();
337 mockTargetSource.setTarget(bean);
338
339 AdvisedSupport as = new AdvisedSupport(new Class<?>[]{});
340 as.setTargetSource(mockTargetSource);
341 as.addAdvice(new NopInterceptor());
342 AopProxy aop = new CglibAopProxy(as);
343
344 ExceptionThrower proxy = (ExceptionThrower) aop.getProxy();
345
346 try {
347 proxy.doTest();
348 }
349 catch (Exception ex) {
350 assertTrue("Invalid exception class", ex instanceof ApplicationContextException);
351 }
352
353 assertTrue("Catch was not invoked", proxy.isCatchInvoked());
354 assertTrue("Finally was not invoked", proxy.isFinallyInvoked());
355 }
356
357 @Test
358 @SuppressWarnings("resource")
359 public void testWithDependencyChecking() {
360 ApplicationContext ctx = new ClassPathXmlApplicationContext(DEPENDENCY_CHECK_CONTEXT, getClass());
361 ctx.getBean("testBean");
362 }
363
364 @Test
365 public void testAddAdviceAtRuntime() {
366 TestBean bean = new TestBean();
367 CountingBeforeAdvice cba = new CountingBeforeAdvice();
368
369 ProxyFactory pf = new ProxyFactory();
370 pf.setTarget(bean);
371 pf.setFrozen(false);
372 pf.setOpaque(false);
373 pf.setProxyTargetClass(true);
374
375 TestBean proxy = (TestBean) pf.getProxy();
376 assertTrue(AopUtils.isCglibProxy(proxy));
377
378 proxy.getAge();
379 assertEquals(0, cba.getCalls());
380
381 ((Advised) proxy).addAdvice(cba);
382 proxy.getAge();
383 assertEquals(1, cba.getCalls());
384 }
385
386 @Test
387 public void testProxyProtectedMethod() throws Exception {
388 CountingBeforeAdvice advice = new CountingBeforeAdvice();
389 ProxyFactory proxyFactory = new ProxyFactory(new MyBean());
390 proxyFactory.addAdvice(advice);
391 proxyFactory.setProxyTargetClass(true);
392
393 MyBean proxy = (MyBean) proxyFactory.getProxy();
394 assertEquals(4, proxy.add(1, 3));
395 assertEquals(1, advice.getCalls("add"));
396 }
397
398 @Test
399 public void testProxyTargetClassInCaseOfNoInterfaces() throws Exception {
400 ProxyFactory proxyFactory = new ProxyFactory(new MyBean());
401 MyBean proxy = (MyBean) proxyFactory.getProxy();
402 assertEquals(4, proxy.add(1, 3));
403 }
404
405
406 public static class MyBean {
407
408 private String name;
409
410 public String getName() {
411 return name;
412 }
413
414 public void setName(String name) {
415 this.name = name;
416 }
417
418 protected int add(int x, int y) {
419 return x + y;
420 }
421 }
422
423
424 public static class ExceptionThrower {
425
426 private boolean catchInvoked;
427
428 private boolean finallyInvoked;
429
430 public boolean isCatchInvoked() {
431 return catchInvoked;
432 }
433
434 public boolean isFinallyInvoked() {
435 return finallyInvoked;
436 }
437
438 public void doTest() throws Exception {
439 try {
440 throw new ApplicationContextException("foo");
441 }
442 catch (Exception ex) {
443 catchInvoked = true;
444 throw ex;
445 }
446 finally {
447 finallyInvoked = true;
448 }
449 }
450 }
451
452
453 public static class NoArgCtorTestBean {
454
455 private boolean called = false;
456
457 public NoArgCtorTestBean(String x, int y) {
458 called = true;
459 }
460
461 public boolean wasCalled() {
462 return called;
463 }
464
465 public void reset() {
466 called = false;
467 }
468 }
469
470
471 public static class ProtectedMethodTestBean {
472
473 public String value;
474
475 protected String getString() {
476 return this.value;
477 }
478 }
479
480
481 public static class PackageMethodTestBean {
482
483 public String value;
484
485 String getString() {
486 return this.value;
487 }
488 }
489 }
490
491
492 class CglibTestBean {
493
494 private String name;
495
496 public CglibTestBean() {
497 setName("Some Default");
498 }
499
500 public void setName(String name) {
501 this.name = name;
502 }
503
504 public String getName() {
505 return this.name;
506 }
507 }
508
509
510 class UnsupportedInterceptor implements MethodInterceptor {
511
512 @Override
513 public Object invoke(MethodInvocation mi) throws Throwable {
514 throw new UnsupportedOperationException(mi.getMethod().getName());
515 }
516 }