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.FileNotFoundException;
20 import java.io.IOException;
21 import java.lang.reflect.Method;
22 import java.lang.reflect.UndeclaredThrowableException;
23 import java.rmi.MarshalException;
24 import java.sql.SQLException;
25 import java.util.HashMap;
26 import java.util.Iterator;
27 import java.util.LinkedList;
28 import java.util.List;
29 import java.util.Map;
30
31 import junit.framework.TestCase;
32 import org.aopalliance.aop.Advice;
33 import org.aopalliance.intercept.MethodInterceptor;
34 import org.aopalliance.intercept.MethodInvocation;
35 import org.junit.After;
36 import org.junit.Before;
37 import org.junit.Test;
38 import test.mixin.LockMixin;
39 import test.mixin.LockMixinAdvisor;
40 import test.mixin.Lockable;
41 import test.mixin.LockedException;
42
43 import org.springframework.aop.Advisor;
44 import org.springframework.aop.AfterReturningAdvice;
45 import org.springframework.aop.DynamicIntroductionAdvice;
46 import org.springframework.aop.MethodBeforeAdvice;
47 import org.springframework.aop.TargetSource;
48 import org.springframework.aop.ThrowsAdvice;
49 import org.springframework.aop.interceptor.DebugInterceptor;
50 import org.springframework.aop.interceptor.ExposeInvocationInterceptor;
51 import org.springframework.aop.support.AopUtils;
52 import org.springframework.aop.support.DefaultIntroductionAdvisor;
53 import org.springframework.aop.support.DefaultPointcutAdvisor;
54 import org.springframework.aop.support.DelegatingIntroductionInterceptor;
55 import org.springframework.aop.support.DynamicMethodMatcherPointcut;
56 import org.springframework.aop.support.NameMatchMethodPointcut;
57 import org.springframework.aop.support.Pointcuts;
58 import org.springframework.aop.support.StaticMethodMatcherPointcutAdvisor;
59 import org.springframework.aop.target.HotSwappableTargetSource;
60 import org.springframework.aop.target.SingletonTargetSource;
61 import org.springframework.tests.Assume;
62 import org.springframework.tests.TestGroup;
63 import org.springframework.tests.TimeStamped;
64 import org.springframework.tests.aop.advice.CountingAfterReturningAdvice;
65 import org.springframework.tests.aop.advice.CountingBeforeAdvice;
66 import org.springframework.tests.aop.advice.MethodCounter;
67 import org.springframework.tests.aop.advice.MyThrowsHandler;
68 import org.springframework.tests.aop.interceptor.NopInterceptor;
69 import org.springframework.tests.aop.interceptor.SerializableNopInterceptor;
70 import org.springframework.tests.aop.interceptor.TimestampIntroductionInterceptor;
71 import org.springframework.tests.sample.beans.IOther;
72 import org.springframework.tests.sample.beans.ITestBean;
73 import org.springframework.tests.sample.beans.Person;
74 import org.springframework.tests.sample.beans.SerializablePerson;
75 import org.springframework.tests.sample.beans.TestBean;
76 import org.springframework.util.SerializationTestUtils;
77 import org.springframework.util.StopWatch;
78
79 import static org.junit.Assert.*;
80
81
82
83
84
85
86
87 public abstract class AbstractAopProxyTests {
88
89 protected final MockTargetSource mockTargetSource = new MockTargetSource();
90
91
92
93
94
95
96
97 @Before
98 public void setUp() {
99 mockTargetSource.reset();
100 }
101
102 @After
103 public void tearDown() {
104 mockTargetSource.verify();
105 }
106
107
108
109
110
111 protected abstract Object createProxy(ProxyCreatorSupport as);
112
113 protected abstract AopProxy createAopProxy(AdvisedSupport as);
114
115
116
117
118 protected boolean requiresTarget() {
119 return false;
120 }
121
122
123 @Test
124 public void testNoInterceptorsAndNoTarget() {
125 AdvisedSupport pc = new AdvisedSupport(new Class<?>[] {ITestBean.class});
126
127 try {
128 AopProxy aop = createAopProxy(pc);
129 aop.getProxy();
130 fail("Shouldn't allow no interceptors");
131 }
132 catch (AopConfigException ex) {
133
134 }
135 }
136
137
138
139
140 @Test
141 public void testValuesStick() {
142 int age1 = 33;
143 int age2 = 37;
144 String name = "tony";
145
146 TestBean target1 = new TestBean();
147 target1.setAge(age1);
148 ProxyFactory pf1 = new ProxyFactory(target1);
149 pf1.addAdvisor(new DefaultPointcutAdvisor(new NopInterceptor()));
150 pf1.addAdvisor(new DefaultPointcutAdvisor(new TimestampIntroductionInterceptor()));
151 ITestBean tb = (ITestBean) pf1.getProxy();
152
153 assertEquals(age1, tb.getAge());
154 tb.setAge(age2);
155 assertEquals(age2, tb.getAge());
156 assertNull(tb.getName());
157 tb.setName(name);
158 assertEquals(name, tb.getName());
159 }
160
161
162
163
164
165
166 @Test
167 public void testManyProxies() {
168 Assume.group(TestGroup.PERFORMANCE);
169 int howMany = 10000;
170 StopWatch sw = new StopWatch();
171 sw.start("Create " + howMany + " proxies");
172 testManyProxies(howMany);
173 sw.stop();
174 System.out.println(sw.getTotalTimeMillis());
175 assertTrue("Proxy creation was too slow", sw.getTotalTimeMillis() < 5000);
176 }
177
178 private void testManyProxies(int howMany) {
179 int age1 = 33;
180 TestBean target1 = new TestBean();
181 target1.setAge(age1);
182 ProxyFactory pf1 = new ProxyFactory(target1);
183 pf1.addAdvice(new NopInterceptor());
184 pf1.addAdvice(new NopInterceptor());
185 ITestBean proxies[] = new ITestBean[howMany];
186 for (int i = 0; i < howMany; i++) {
187 proxies[i] = (ITestBean) createAopProxy(pf1).getProxy();
188 assertEquals(age1, proxies[i].getAge());
189 }
190 }
191
192 @Test
193 public void testSerializationAdviceAndTargetNotSerializable() throws Exception {
194 TestBean tb = new TestBean();
195 assertFalse(SerializationTestUtils.isSerializable(tb));
196
197 ProxyFactory pf = new ProxyFactory(tb);
198
199 pf.addAdvice(new NopInterceptor());
200 ITestBean proxy = (ITestBean) createAopProxy(pf).getProxy();
201
202 assertFalse(SerializationTestUtils.isSerializable(proxy));
203 }
204
205 @Test
206 public void testSerializationAdviceNotSerializable() throws Exception {
207 SerializablePerson sp = new SerializablePerson();
208 assertTrue(SerializationTestUtils.isSerializable(sp));
209
210 ProxyFactory pf = new ProxyFactory(sp);
211
212
213 Advice i = new NopInterceptor();
214 pf.addAdvice(i);
215 assertFalse(SerializationTestUtils.isSerializable(i));
216 Object proxy = createAopProxy(pf).getProxy();
217
218 assertFalse(SerializationTestUtils.isSerializable(proxy));
219 }
220
221 @Test
222 public void testSerializationSerializableTargetAndAdvice() throws Throwable {
223 SerializablePerson personTarget = new SerializablePerson();
224 personTarget.setName("jim");
225 personTarget.setAge(26);
226
227 assertTrue(SerializationTestUtils.isSerializable(personTarget));
228
229 ProxyFactory pf = new ProxyFactory(personTarget);
230
231 CountingThrowsAdvice cta = new CountingThrowsAdvice();
232
233 pf.addAdvice(new SerializableNopInterceptor());
234
235 pf.addAdvice(new CountingBeforeAdvice());
236 pf.addAdvice(new CountingAfterReturningAdvice());
237 pf.addAdvice(cta);
238 Person p = (Person) createAopProxy(pf).getProxy();
239
240 p.echo(null);
241 assertEquals(0, cta.getCalls());
242 try {
243 p.echo(new IOException());
244 }
245 catch (IOException ex) {
246
247 }
248 assertEquals(1, cta.getCalls());
249
250
251 Person p2 = (Person) SerializationTestUtils.serializeAndDeserialize(p);
252 assertNotSame(p, p2);
253 assertEquals(p.getName(), p2.getName());
254 assertEquals(p.getAge(), p2.getAge());
255 assertTrue("Deserialized object is an AOP proxy", AopUtils.isAopProxy(p2));
256
257 Advised a1 = (Advised) p;
258 Advised a2 = (Advised) p2;
259
260 assertEquals(a1.getAdvisors().length, a2.getAdvisors().length);
261
262
263 assertEquals("Proxies should be equal, even after one was serialized", p, p2);
264 assertEquals("Proxies should be equal, even after one was serialized", p2, p);
265
266
267 NopInterceptor ni = new NopInterceptor();
268 p2.getAge();
269 assertEquals(0, ni.getCount());
270 a2.addAdvice(ni);
271 p2.getAge();
272 assertEquals(1, ni.getCount());
273
274 cta = (CountingThrowsAdvice) a2.getAdvisors()[3].getAdvice();
275 p2.echo(null);
276 assertEquals(1, cta.getCalls());
277 try {
278 p2.echo(new IOException());
279 }
280 catch (IOException ex) {
281
282 }
283 assertEquals(2, cta.getCalls());
284
285 }
286
287
288
289
290
291
292 @Test
293 public void testOneAdvisedObjectCallsAnother() {
294 int age1 = 33;
295 int age2 = 37;
296
297 TestBean target1 = new TestBean();
298 ProxyFactory pf1 = new ProxyFactory(target1);
299
300 pf1.setExposeProxy(true);
301 NopInterceptor di1 = new NopInterceptor();
302 pf1.addAdvice(0, di1);
303 pf1.addAdvice(1, new ProxyMatcherInterceptor());
304 pf1.addAdvice(2, new CheckMethodInvocationIsSameInAndOutInterceptor());
305 pf1.addAdvice(1, new CheckMethodInvocationViaThreadLocalIsSameInAndOutInterceptor());
306
307 pf1.addAdvice(0, ExposeInvocationInterceptor.INSTANCE);
308 ITestBean advised1 = (ITestBean) pf1.getProxy();
309 advised1.setAge(age1);
310
311 TestBean target2 = new TestBean();
312 ProxyFactory pf2 = new ProxyFactory(target2);
313 pf2.setExposeProxy(true);
314 NopInterceptor di2 = new NopInterceptor();
315 pf2.addAdvice(0, di2);
316 pf2.addAdvice(1, new ProxyMatcherInterceptor());
317 pf2.addAdvice(2, new CheckMethodInvocationIsSameInAndOutInterceptor());
318 pf2.addAdvice(1, new CheckMethodInvocationViaThreadLocalIsSameInAndOutInterceptor());
319 pf2.addAdvice(0, ExposeInvocationInterceptor.INSTANCE);
320
321 ITestBean advised2 = (ITestBean) createProxy(pf2);
322 advised2.setAge(age2);
323 advised1.setSpouse(advised2);
324
325 assertEquals("Advised one has correct age", age1, advised1.getAge());
326 assertEquals("Advised two has correct age", age2, advised2.getAge());
327
328 assertEquals("Advised one spouse has correct age", age2, advised1.getSpouse().getAge());
329
330 assertEquals("one was invoked correct number of times", 4, di1.getCount());
331
332 assertEquals("one was invoked correct number of times", 3, di2.getCount());
333 }
334
335
336 @Test
337 public void testReentrance() {
338 int age1 = 33;
339
340 TestBean target1 = new TestBean();
341 ProxyFactory pf1 = new ProxyFactory(target1);
342 NopInterceptor di1 = new NopInterceptor();
343 pf1.addAdvice(0, di1);
344 ITestBean advised1 = (ITestBean) createProxy(pf1);
345 advised1.setAge(age1);
346 advised1.setSpouse(advised1);
347
348 assertEquals("one was invoked correct number of times", 2, di1.getCount());
349
350 assertEquals("Advised one has correct age", age1, advised1.getAge());
351 assertEquals("one was invoked correct number of times", 3, di1.getCount());
352
353
354 assertEquals("Advised spouse has correct age", age1, advised1.getSpouse().getAge());
355
356 assertEquals("one was invoked correct number of times", 5, di1.getCount());
357 }
358
359 @Test
360 public void testTargetCanGetProxy() {
361 NopInterceptor di = new NopInterceptor();
362 INeedsToSeeProxy target = new TargetChecker();
363 ProxyFactory proxyFactory = new ProxyFactory(target);
364 proxyFactory.setExposeProxy(true);
365 assertTrue(proxyFactory.isExposeProxy());
366
367 proxyFactory.addAdvice(0, di);
368 INeedsToSeeProxy proxied = (INeedsToSeeProxy) createProxy(proxyFactory);
369 assertEquals(0, di.getCount());
370 assertEquals(0, target.getCount());
371 proxied.incrementViaThis();
372 assertEquals("Increment happened", 1, target.getCount());
373
374 assertEquals("Only one invocation via AOP as use of this wasn't proxied", 1, di.getCount());
375
376 assertEquals("Increment happened", 1, proxied.getCount());
377 proxied.incrementViaProxy();
378 assertEquals("Increment happened", 2, target.getCount());
379 assertEquals("3 more invocations via AOP as the first call was reentrant through the proxy", 4, di.getCount());
380 }
381
382
383 @Test
384 public void testTargetCantGetProxyByDefault() {
385 NeedsToSeeProxy et = new NeedsToSeeProxy();
386 ProxyFactory pf1 = new ProxyFactory(et);
387 assertFalse(pf1.isExposeProxy());
388 INeedsToSeeProxy proxied = (INeedsToSeeProxy) createProxy(pf1);
389 try {
390 proxied.incrementViaProxy();
391 fail("Should have failed to get proxy as exposeProxy wasn't set to true");
392 }
393 catch (IllegalStateException ex) {
394
395 }
396 }
397
398 @Test
399 public void testContext() throws Throwable {
400 testContext(true);
401 }
402
403 @Test
404 public void testNoContext() throws Throwable {
405 testContext(false);
406 }
407
408
409
410
411 private void testContext(final boolean context) throws Throwable {
412 final String s = "foo";
413
414 MethodInterceptor mi = new MethodInterceptor() {
415 @Override
416 public Object invoke(MethodInvocation invocation) throws Throwable {
417 if (!context) {
418 assertNoInvocationContext();
419 } else {
420 assertTrue("have context", ExposeInvocationInterceptor.currentInvocation() != null);
421 }
422 return s;
423 }
424 };
425 AdvisedSupport pc = new AdvisedSupport(new Class<?>[] {ITestBean.class});
426 if (context) {
427 pc.addAdvice(ExposeInvocationInterceptor.INSTANCE);
428 }
429 pc.addAdvice(mi);
430
431 if (requiresTarget()) {
432 pc.setTarget(new TestBean());
433 }
434 AopProxy aop = createAopProxy(pc);
435
436 assertNoInvocationContext();
437 ITestBean tb = (ITestBean) aop.getProxy();
438 assertNoInvocationContext();
439 assertTrue("correct return value", tb.getName() == s);
440 }
441
442
443
444
445
446 @Test
447 public void testTargetReturnsThis() throws Throwable {
448
449 TestBean raw = new OwnSpouse();
450
451 ProxyCreatorSupport pc = new ProxyCreatorSupport();
452 pc.setInterfaces(new Class<?>[] {ITestBean.class});
453 pc.setTarget(raw);
454
455 ITestBean tb = (ITestBean) createProxy(pc);
456 assertTrue("this return is wrapped in proxy", tb.getSpouse() == tb);
457 }
458
459 @Test
460 public void testDeclaredException() throws Throwable {
461 final Exception expectedException = new Exception();
462
463 MethodInterceptor mi = new MethodInterceptor() {
464 @Override
465 public Object invoke(MethodInvocation invocation) throws Throwable {
466 throw expectedException;
467 }
468 };
469 AdvisedSupport pc = new AdvisedSupport(new Class<?>[] {ITestBean.class});
470 pc.addAdvice(ExposeInvocationInterceptor.INSTANCE);
471 pc.addAdvice(mi);
472
473
474 mockTargetSource.setTarget(new Object());
475 pc.setTargetSource(mockTargetSource);
476 AopProxy aop = createAopProxy(pc);
477
478 try {
479 ITestBean tb = (ITestBean) aop.getProxy();
480
481 tb.exceptional(expectedException);
482 fail("Should have thrown exception raised by interceptor");
483 }
484 catch (Exception thrown) {
485 assertEquals("exception matches", expectedException, thrown);
486 }
487 }
488
489
490
491
492
493
494 @Test
495 public void testUndeclaredCheckedException() throws Throwable {
496 final Exception unexpectedException = new Exception();
497
498 MethodInterceptor mi = new MethodInterceptor() {
499 @Override
500 public Object invoke(MethodInvocation invocation) throws Throwable {
501 throw unexpectedException;
502 }
503 };
504 AdvisedSupport pc = new AdvisedSupport(new Class<?>[] {ITestBean.class});
505 pc.addAdvice(ExposeInvocationInterceptor.INSTANCE);
506 pc.addAdvice(mi);
507
508
509 pc.setTarget(new TestBean());
510 AopProxy aop = createAopProxy(pc);
511 ITestBean tb = (ITestBean) aop.getProxy();
512
513 try {
514
515 tb.getAge();
516 fail("Should have wrapped exception raised by interceptor");
517 }
518 catch (UndeclaredThrowableException thrown) {
519 assertEquals("exception matches", unexpectedException, thrown.getUndeclaredThrowable());
520 }
521 catch (Exception ex) {
522 ex.printStackTrace();
523 fail("Didn't expect exception: " + ex);
524 }
525 }
526
527 @Test
528 public void testUndeclaredUnheckedException() throws Throwable {
529 final RuntimeException unexpectedException = new RuntimeException();
530
531 MethodInterceptor mi = new MethodInterceptor() {
532 @Override
533 public Object invoke(MethodInvocation invocation) throws Throwable {
534 throw unexpectedException;
535 }
536 };
537 AdvisedSupport pc = new AdvisedSupport(new Class<?>[] {ITestBean.class});
538 pc.addAdvice(ExposeInvocationInterceptor.INSTANCE);
539 pc.addAdvice(mi);
540
541
542 pc.setTarget(new TestBean());
543 AopProxy aop = createAopProxy(pc);
544 ITestBean tb = (ITestBean) aop.getProxy();
545
546 try {
547
548 tb.getAge();
549 fail("Should have wrapped exception raised by interceptor");
550 }
551 catch (RuntimeException thrown) {
552 assertEquals("exception matches", unexpectedException, thrown);
553 }
554 }
555
556
557
558
559
560
561
562 @Test
563 public void testTargetCanGetInvocationEvenIfNoAdviceChain() throws Throwable {
564 NeedsToSeeProxy target = new NeedsToSeeProxy();
565 AdvisedSupport pc = new AdvisedSupport(new Class<?>[] {INeedsToSeeProxy.class});
566 pc.setTarget(target);
567 pc.setExposeProxy(true);
568
569
570 AopProxy aop = createAopProxy(pc);
571 INeedsToSeeProxy proxied = (INeedsToSeeProxy) aop.getProxy();
572
573 proxied.incrementViaProxy();
574 }
575
576 @Test
577 public void testTargetCanGetInvocation() throws Throwable {
578 final InvocationCheckExposedInvocationTestBean expectedTarget = new InvocationCheckExposedInvocationTestBean();
579
580 AdvisedSupport pc = new AdvisedSupport(new Class<?>[] {ITestBean.class, IOther.class});
581 pc.addAdvice(ExposeInvocationInterceptor.INSTANCE);
582 TrapTargetInterceptor tii = new TrapTargetInterceptor() {
583 @Override
584 public Object invoke(MethodInvocation invocation) throws Throwable {
585
586 assertEquals("Target is correct", expectedTarget, invocation.getThis());
587 return super.invoke(invocation);
588 }
589 };
590 pc.addAdvice(tii);
591 pc.setTarget(expectedTarget);
592 AopProxy aop = createAopProxy(pc);
593
594 ITestBean tb = (ITestBean) aop.getProxy();
595 tb.getName();
596
597
598
599
600
601
602
603
604
605 }
606
607
608
609
610 private void assertNoInvocationContext() {
611 try {
612 ExposeInvocationInterceptor.currentInvocation();
613 fail("Expected no invocation context");
614 }
615 catch (IllegalStateException ex) {
616
617 }
618 }
619
620
621
622
623 @Test
624 public void testMixinWithIntroductionAdvisor() throws Throwable {
625 TestBean tb = new TestBean();
626 ProxyFactory pc = new ProxyFactory(new Class<?>[] {ITestBean.class});
627 pc.addAdvisor(new LockMixinAdvisor());
628 pc.setTarget(tb);
629
630 testTestBeanIntroduction(pc);
631 }
632
633 @Test
634 public void testMixinWithIntroductionInfo() throws Throwable {
635 TestBean tb = new TestBean();
636 ProxyFactory pc = new ProxyFactory(new Class<?>[] {ITestBean.class});
637
638 pc.addAdvice(new LockMixin());
639 pc.setTarget(tb);
640
641 testTestBeanIntroduction(pc);
642 }
643
644 private void testTestBeanIntroduction(ProxyFactory pc) {
645 int newAge = 65;
646 ITestBean itb = (ITestBean) createProxy(pc);
647 itb.setAge(newAge);
648 assertTrue(itb.getAge() == newAge);
649
650 Lockable lockable = (Lockable) itb;
651 assertFalse(lockable.locked());
652 lockable.lock();
653
654 assertTrue(itb.getAge() == newAge);
655 try {
656 itb.setAge(1);
657 fail("Setters should fail when locked");
658 }
659 catch (LockedException ex) {
660
661 }
662 assertTrue(itb.getAge() == newAge);
663
664
665 assertTrue(lockable.locked());
666 lockable.unlock();
667 itb.setAge(1);
668 assertTrue(itb.getAge() == 1);
669 }
670
671
672 @Test
673 public void testReplaceArgument() throws Throwable {
674 TestBean tb = new TestBean();
675 ProxyFactory pc = new ProxyFactory(new Class<?>[] {ITestBean.class});
676 pc.setTarget(tb);
677 pc.addAdvisor(new StringSetterNullReplacementAdvice());
678
679 ITestBean t = (ITestBean) pc.getProxy();
680 int newAge = 5;
681 t.setAge(newAge);
682 assertTrue(t.getAge() == newAge);
683 String newName = "greg";
684 t.setName(newName);
685 assertEquals(newName, t.getName());
686
687 t.setName(null);
688
689 assertTrue(t.getName().equals(""));
690 }
691
692 @Test
693 public void testCanCastProxyToProxyConfig() throws Throwable {
694 TestBean tb = new TestBean();
695 ProxyFactory pc = new ProxyFactory(tb);
696 NopInterceptor di = new NopInterceptor();
697 pc.addAdvice(0, di);
698
699 ITestBean t = (ITestBean) createProxy(pc);
700 assertEquals(0, di.getCount());
701 t.setAge(23);
702 assertEquals(23, t.getAge());
703 assertEquals(2, di.getCount());
704
705 Advised advised = (Advised) t;
706 assertEquals("Have 1 advisor", 1, advised.getAdvisors().length);
707 assertEquals(di, advised.getAdvisors()[0].getAdvice());
708 NopInterceptor di2 = new NopInterceptor();
709 advised.addAdvice(1, di2);
710 t.getName();
711 assertEquals(3, di.getCount());
712 assertEquals(1, di2.getCount());
713
714 advised.removeAdvisor(0);
715 t.getAge();
716
717 assertEquals(3, di.getCount());
718 assertEquals(2, di2.getCount());
719
720 CountingBeforeAdvice cba = new CountingBeforeAdvice();
721 assertEquals(0, cba.getCalls());
722 advised.addAdvice(cba);
723 t.setAge(16);
724 assertEquals(16, t.getAge());
725 assertEquals(2, cba.getCalls());
726 }
727
728 @Test
729 public void testAdviceImplementsIntroductionInfo() throws Throwable {
730 TestBean tb = new TestBean();
731 String name = "tony";
732 tb.setName(name);
733 ProxyFactory pc = new ProxyFactory(tb);
734 NopInterceptor di = new NopInterceptor();
735 pc.addAdvice(di);
736 final long ts = 37;
737 pc.addAdvice(new DelegatingIntroductionInterceptor(new TimeStamped() {
738 @Override
739 public long getTimeStamp() {
740 return ts;
741 }
742 }));
743
744 ITestBean proxied = (ITestBean) createProxy(pc);
745 assertEquals(name, proxied.getName());
746 TimeStamped intro = (TimeStamped) proxied;
747 assertEquals(ts, intro.getTimeStamp());
748 }
749
750 @Test
751 public void testCannotAddDynamicIntroductionAdviceExceptInIntroductionAdvice() throws Throwable {
752 TestBean target = new TestBean();
753 target.setAge(21);
754 ProxyFactory pc = new ProxyFactory(target);
755 try {
756 pc.addAdvice(new DummyIntroductionAdviceImpl());
757 fail("Shouldn't be able to add introduction interceptor except via introduction advice");
758 }
759 catch (AopConfigException ex) {
760 assertTrue(ex.getMessage().indexOf("ntroduction") > -1);
761 }
762
763 ITestBean proxied = (ITestBean) createProxy(pc);
764 assertEquals(target.getAge(), proxied.getAge());
765 }
766
767 @Test
768 public void testRejectsBogusDynamicIntroductionAdviceWithNoAdapter() throws Throwable {
769 TestBean target = new TestBean();
770 target.setAge(21);
771 ProxyFactory pc = new ProxyFactory(target);
772 pc.addAdvisor(new DefaultIntroductionAdvisor(new DummyIntroductionAdviceImpl(), Comparable.class));
773 try {
774
775 ITestBean proxied = (ITestBean) createProxy(pc);
776 proxied.getName();
777 fail("Bogus introduction");
778 }
779 catch (Exception ex) {
780
781
782
783
784 }
785 }
786
787
788
789
790
791 @Test
792 public void testCannotAddIntroductionAdviceWithUnimplementedInterface() throws Throwable {
793 TestBean target = new TestBean();
794 target.setAge(21);
795 ProxyFactory pc = new ProxyFactory(target);
796 try {
797 pc.addAdvisor(0, new DefaultIntroductionAdvisor(new TimestampIntroductionInterceptor(), ITestBean.class));
798 fail("Shouldn't be able to add introduction advice introducing an unimplemented interface");
799 }
800 catch (IllegalArgumentException ex) {
801
802 }
803
804 ITestBean proxied = (ITestBean) createProxy(pc);
805 assertEquals(target.getAge(), proxied.getAge());
806 }
807
808
809
810
811
812 @Test
813 public void testIntroductionThrowsUncheckedException() throws Throwable {
814 TestBean target = new TestBean();
815 target.setAge(21);
816 ProxyFactory pc = new ProxyFactory(target);
817
818 @SuppressWarnings("serial")
819 class MyDi extends DelegatingIntroductionInterceptor implements TimeStamped {
820
821
822
823 @Override
824 public long getTimeStamp() {
825 throw new UnsupportedOperationException();
826 }
827 }
828 pc.addAdvisor(new DefaultIntroductionAdvisor(new MyDi()));
829
830 TimeStamped ts = (TimeStamped) createProxy(pc);
831 try {
832 ts.getTimeStamp();
833 fail("Should throw UnsupportedOperationException");
834 }
835 catch (UnsupportedOperationException ex) {
836 }
837 }
838
839
840
841
842 @Test
843 public void testCannotAddIntroductionAdviceToIntroduceClass() throws Throwable {
844 TestBean target = new TestBean();
845 target.setAge(21);
846 ProxyFactory pc = new ProxyFactory(target);
847 try {
848 pc.addAdvisor(0, new DefaultIntroductionAdvisor(new TimestampIntroductionInterceptor(), TestBean.class));
849 fail("Shouldn't be able to add introduction advice that introduces a class, rather than an interface");
850 }
851 catch (IllegalArgumentException ex) {
852 assertTrue(ex.getMessage().indexOf("interface") > -1);
853 }
854
855 ITestBean proxied = (ITestBean) createProxy(pc);
856 assertEquals(target.getAge(), proxied.getAge());
857 }
858
859 @Test
860 public void testCannotAddInterceptorWhenFrozen() throws Throwable {
861 TestBean target = new TestBean();
862 target.setAge(21);
863 ProxyFactory pc = new ProxyFactory(target);
864 assertFalse(pc.isFrozen());
865 pc.addAdvice(new NopInterceptor());
866 ITestBean proxied = (ITestBean) createProxy(pc);
867 pc.setFrozen(true);
868 try {
869 pc.addAdvice(0, new NopInterceptor());
870 fail("Shouldn't be able to add interceptor when frozen");
871 }
872 catch (AopConfigException ex) {
873 assertTrue(ex.getMessage().indexOf("frozen") > -1);
874 }
875
876 assertEquals(target.getAge(), proxied.getAge());
877 assertEquals(1, ((Advised) proxied).getAdvisors().length);
878 }
879
880
881
882
883 @Test
884 public void testCannotAddAdvisorWhenFrozenUsingCast() throws Throwable {
885 TestBean target = new TestBean();
886 target.setAge(21);
887 ProxyFactory pc = new ProxyFactory(target);
888 assertFalse(pc.isFrozen());
889 pc.addAdvice(new NopInterceptor());
890 ITestBean proxied = (ITestBean) createProxy(pc);
891 pc.setFrozen(true);
892 Advised advised = (Advised) proxied;
893
894 assertTrue(pc.isFrozen());
895 try {
896 advised.addAdvisor(new DefaultPointcutAdvisor(new NopInterceptor()));
897 fail("Shouldn't be able to add Advisor when frozen");
898 }
899 catch (AopConfigException ex) {
900 assertTrue(ex.getMessage().indexOf("frozen") > -1);
901 }
902
903 assertEquals(target.getAge(), proxied.getAge());
904 assertEquals(1, advised.getAdvisors().length);
905 }
906
907 @Test
908 public void testCannotRemoveAdvisorWhenFrozen() throws Throwable {
909 TestBean target = new TestBean();
910 target.setAge(21);
911 ProxyFactory pc = new ProxyFactory(target);
912 assertFalse(pc.isFrozen());
913 pc.addAdvice(new NopInterceptor());
914 ITestBean proxied = (ITestBean) createProxy(pc);
915 pc.setFrozen(true);
916 Advised advised = (Advised) proxied;
917
918 assertTrue(pc.isFrozen());
919 try {
920 advised.removeAdvisor(0);
921 fail("Shouldn't be able to remove Advisor when frozen");
922 }
923 catch (AopConfigException ex) {
924 assertTrue(ex.getMessage().indexOf("frozen") > -1);
925 }
926
927 assertEquals(1, advised.getAdvisors().length);
928 pc.setFrozen(false);
929
930 advised.removeAdvisor(0);
931
932 assertEquals(target.getAge(), proxied.getAge());
933 assertEquals(0, advised.getAdvisors().length);
934 }
935
936 @Test
937 public void testUseAsHashKey() {
938 TestBean target1 = new TestBean();
939 ProxyFactory pf1 = new ProxyFactory(target1);
940 pf1.addAdvice(new NopInterceptor());
941 ITestBean proxy1 = (ITestBean) createProxy(pf1);
942
943 TestBean target2 = new TestBean();
944 ProxyFactory pf2 = new ProxyFactory(target2);
945 pf2.addAdvisor(new DefaultIntroductionAdvisor(new TimestampIntroductionInterceptor()));
946 ITestBean proxy2 = (ITestBean) createProxy(pf2);
947
948 HashMap<ITestBean, Object> h = new HashMap<ITestBean, Object>();
949 Object value1 = "foo";
950 Object value2 = "bar";
951 assertNull(h.get(proxy1));
952 h.put(proxy1, value1);
953 h.put(proxy2, value2);
954 assertEquals(h.get(proxy1), value1);
955 assertEquals(h.get(proxy2), value2);
956 }
957
958
959
960
961 @Test
962 public void testProxyConfigString() {
963 TestBean target = new TestBean();
964 ProxyFactory pc = new ProxyFactory(target);
965 pc.setInterfaces(new Class<?>[] {ITestBean.class});
966 pc.addAdvice(new NopInterceptor());
967 MethodBeforeAdvice mba = new CountingBeforeAdvice();
968 Advisor advisor = new DefaultPointcutAdvisor(new NameMatchMethodPointcut(), mba);
969 pc.addAdvisor(advisor);
970 ITestBean proxied = (ITestBean) createProxy(pc);
971
972 String proxyConfigString = ((Advised) proxied).toProxyConfigString();
973 assertTrue(proxyConfigString.indexOf(advisor.toString()) != -1);
974 assertTrue(proxyConfigString.indexOf("1 interface") != -1);
975 }
976
977 @Test
978 public void testCanPreventCastToAdvisedUsingOpaque() {
979 TestBean target = new TestBean();
980 ProxyFactory pc = new ProxyFactory(target);
981 pc.setInterfaces(new Class<?>[] {ITestBean.class});
982 pc.addAdvice(new NopInterceptor());
983 CountingBeforeAdvice mba = new CountingBeforeAdvice();
984 Advisor advisor = new DefaultPointcutAdvisor(new NameMatchMethodPointcut().addMethodName("setAge"), mba);
985 pc.addAdvisor(advisor);
986 assertFalse("Opaque defaults to false", pc.isOpaque());
987 pc.setOpaque(true);
988 assertTrue("Opaque now true for this config", pc.isOpaque());
989 ITestBean proxied = (ITestBean) createProxy(pc);
990 proxied.setAge(10);
991 assertEquals(10, proxied.getAge());
992 assertEquals(1, mba.getCalls());
993
994 assertFalse("Cannot be cast to Advised", proxied instanceof Advised);
995 }
996
997 @Test
998 public void testAdviceSupportListeners() throws Throwable {
999 TestBean target = new TestBean();
1000 target.setAge(21);
1001
1002 ProxyFactory pc = new ProxyFactory(target);
1003 CountingAdvisorListener l = new CountingAdvisorListener(pc);
1004 pc.addListener(l);
1005 RefreshCountingAdvisorChainFactory acf = new RefreshCountingAdvisorChainFactory();
1006
1007 pc.addListener(acf);
1008 assertFalse(pc.isActive());
1009 assertEquals(0, l.activates);
1010 assertEquals(0, acf.refreshes);
1011 ITestBean proxied = (ITestBean) createProxy(pc);
1012 assertEquals(1, acf.refreshes);
1013 assertEquals(1, l.activates);
1014 assertTrue(pc.isActive());
1015 assertEquals(target.getAge(), proxied.getAge());
1016 assertEquals(0, l.adviceChanges);
1017 NopInterceptor di = new NopInterceptor();
1018 pc.addAdvice(0, di);
1019 assertEquals(1, l.adviceChanges);
1020 assertEquals(2, acf.refreshes);
1021 assertEquals(target.getAge(), proxied.getAge());
1022 pc.removeAdvice(di);
1023 assertEquals(2, l.adviceChanges);
1024 assertEquals(3, acf.refreshes);
1025 assertEquals(target.getAge(), proxied.getAge());
1026 pc.getProxy();
1027 assertEquals(1, l.activates);
1028
1029 pc.removeListener(l);
1030 assertEquals(2, l.adviceChanges);
1031 pc.addAdvisor(new DefaultPointcutAdvisor(new NopInterceptor()));
1032
1033 assertEquals(2, l.adviceChanges);
1034 }
1035
1036 @Test
1037 public void testExistingProxyChangesTarget() throws Throwable {
1038 TestBean tb1 = new TestBean();
1039 tb1.setAge(33);
1040
1041 TestBean tb2 = new TestBean();
1042 tb2.setAge(26);
1043 tb2.setName("Juergen");
1044 TestBean tb3 = new TestBean();
1045 tb3.setAge(37);
1046 ProxyFactory pc = new ProxyFactory(tb1);
1047 NopInterceptor nop = new NopInterceptor();
1048 pc.addAdvice(nop);
1049 ITestBean proxy = (ITestBean) createProxy(pc);
1050 assertEquals(nop.getCount(), 0);
1051 assertEquals(tb1.getAge(), proxy.getAge());
1052 assertEquals(nop.getCount(), 1);
1053
1054 pc.setTarget(tb2);
1055 assertEquals(tb2.getAge(), proxy.getAge());
1056 assertEquals(nop.getCount(), 2);
1057
1058
1059 HotSwappableTargetSource hts = new HotSwappableTargetSource(tb3);
1060 pc.setTargetSource(hts);
1061 assertEquals(tb3.getAge(), proxy.getAge());
1062 assertEquals(nop.getCount(), 3);
1063 hts.swap(tb1);
1064 assertEquals(tb1.getAge(), proxy.getAge());
1065 tb1.setName("Colin");
1066 assertEquals(tb1.getName(), proxy.getName());
1067 assertEquals(nop.getCount(), 5);
1068
1069
1070 Advised advised = (Advised) proxy;
1071 assertSame(hts, advised.getTargetSource());
1072 SingletonTargetSource sts = new SingletonTargetSource(tb2);
1073 advised.setTargetSource(sts);
1074 assertEquals(tb2.getName(), proxy.getName());
1075 assertSame(sts, advised.getTargetSource());
1076 assertEquals(tb2.getAge(), proxy.getAge());
1077 }
1078
1079 @Test
1080 public void testDynamicMethodPointcutThatAlwaysAppliesStatically() throws Throwable {
1081 TestBean tb = new TestBean();
1082 ProxyFactory pc = new ProxyFactory(new Class<?>[] {ITestBean.class});
1083 TestDynamicPointcutAdvice dp = new TestDynamicPointcutAdvice(new NopInterceptor(), "getAge");
1084 pc.addAdvisor(dp);
1085 pc.setTarget(tb);
1086 ITestBean it = (ITestBean) createProxy(pc);
1087 assertEquals(dp.count, 0);
1088 it.getAge();
1089 assertEquals(dp.count, 1);
1090 it.setAge(11);
1091 assertEquals(it.getAge(), 11);
1092 assertEquals(dp.count, 2);
1093 }
1094
1095 @Test
1096 public void testDynamicMethodPointcutThatAppliesStaticallyOnlyToSetters() throws Throwable {
1097 TestBean tb = new TestBean();
1098 ProxyFactory pc = new ProxyFactory(new Class<?>[] {ITestBean.class});
1099
1100 TestDynamicPointcutForSettersOnly dp = new TestDynamicPointcutForSettersOnly(new NopInterceptor(), "Age");
1101 pc.addAdvisor(dp);
1102 this.mockTargetSource.setTarget(tb);
1103 pc.setTargetSource(mockTargetSource);
1104 ITestBean it = (ITestBean) createProxy(pc);
1105 assertEquals(dp.count, 0);
1106 it.getAge();
1107
1108 assertEquals(0, dp.count);
1109 it.setAge(11);
1110 assertEquals(it.getAge(), 11);
1111 assertEquals(dp.count, 1);
1112
1113 it.setName("joe");
1114 assertEquals(dp.count, 1);
1115 }
1116
1117 @Test
1118 public void testStaticMethodPointcut() throws Throwable {
1119 TestBean tb = new TestBean();
1120 ProxyFactory pc = new ProxyFactory(new Class<?>[] {ITestBean.class});
1121 NopInterceptor di = new NopInterceptor();
1122 TestStaticPointcutAdvice sp = new TestStaticPointcutAdvice(di, "getAge");
1123 pc.addAdvisor(sp);
1124 pc.setTarget(tb);
1125 ITestBean it = (ITestBean) createProxy(pc);
1126 assertEquals(di.getCount(), 0);
1127 it.getAge();
1128 assertEquals(di.getCount(), 1);
1129 it.setAge(11);
1130 assertEquals(it.getAge(), 11);
1131 assertEquals(di.getCount(), 2);
1132 }
1133
1134
1135
1136
1137
1138 @Test
1139 public void testCloneInvocationToProceedThreeTimes() throws Throwable {
1140 TestBean tb = new TestBean();
1141 ProxyFactory pc = new ProxyFactory(tb);
1142 pc.addInterface(ITestBean.class);
1143
1144 MethodInterceptor twoBirthdayInterceptor = new MethodInterceptor() {
1145 @Override
1146 public Object invoke(MethodInvocation mi) throws Throwable {
1147
1148
1149 MethodInvocation clone1 = ((ReflectiveMethodInvocation) mi).invocableClone();
1150 MethodInvocation clone2 = ((ReflectiveMethodInvocation) mi).invocableClone();
1151 clone1.proceed();
1152 clone2.proceed();
1153 return mi.proceed();
1154 }
1155 };
1156 @SuppressWarnings("serial")
1157 StaticMethodMatcherPointcutAdvisor advisor = new StaticMethodMatcherPointcutAdvisor(twoBirthdayInterceptor) {
1158 @Override
1159 public boolean matches(Method m, Class<?> targetClass) {
1160 return "haveBirthday".equals(m.getName());
1161 }
1162 };
1163 pc.addAdvisor(advisor);
1164 ITestBean it = (ITestBean) createProxy(pc);
1165
1166 final int age = 20;
1167 it.setAge(age);
1168 assertEquals(age, it.getAge());
1169
1170 assertEquals(age + 2, it.haveBirthday());
1171
1172 assertEquals(age + 3, it.getAge());
1173 }
1174
1175
1176
1177
1178 @Test
1179 public void testCanChangeArgumentsIndependentlyOnClonedInvocation() throws Throwable {
1180 TestBean tb = new TestBean();
1181 ProxyFactory pc = new ProxyFactory(tb);
1182 pc.addInterface(ITestBean.class);
1183
1184
1185
1186
1187 MethodInterceptor nameReverter = new MethodInterceptor() {
1188 @Override
1189 public Object invoke(MethodInvocation mi) throws Throwable {
1190 MethodInvocation clone = ((ReflectiveMethodInvocation) mi).invocableClone();
1191 String oldName = ((ITestBean) mi.getThis()).getName();
1192 clone.getArguments()[0] = oldName;
1193
1194 mi.proceed();
1195 return clone.proceed();
1196 }
1197 };
1198
1199 class NameSaver implements MethodInterceptor {
1200 private List<Object> names = new LinkedList<Object>();
1201
1202 @Override
1203 public Object invoke(MethodInvocation mi) throws Throwable {
1204 names.add(mi.getArguments()[0]);
1205 return mi.proceed();
1206 }
1207 }
1208
1209 NameSaver saver = new NameSaver();
1210
1211 pc.addAdvisor(new DefaultPointcutAdvisor(Pointcuts.SETTERS, nameReverter));
1212 pc.addAdvisor(new DefaultPointcutAdvisor(Pointcuts.SETTERS, saver));
1213 ITestBean it = (ITestBean) createProxy(pc);
1214
1215 String name1 = "tony";
1216 String name2 = "gordon";
1217
1218 tb.setName(name1);
1219 assertEquals(name1, tb.getName());
1220
1221 it.setName(name2);
1222
1223 assertEquals(name1, it.getName());
1224 assertEquals(2, saver.names.size());
1225 assertEquals(name2, saver.names.get(0));
1226 assertEquals(name1, saver.names.get(1));
1227 }
1228
1229 @SuppressWarnings("serial")
1230 @Test
1231 public void testOverloadedMethodsWithDifferentAdvice() throws Throwable {
1232 Overloads target = new Overloads();
1233 ProxyFactory pc = new ProxyFactory(target);
1234 NopInterceptor overLoadVoids = new NopInterceptor();
1235 pc.addAdvisor(new StaticMethodMatcherPointcutAdvisor(overLoadVoids) {
1236 @Override
1237 public boolean matches(Method m, Class<?> targetClass) {
1238 return m.getName().equals("overload") && m.getParameterTypes().length == 0;
1239 }
1240 });
1241 NopInterceptor overLoadInts = new NopInterceptor();
1242 pc.addAdvisor(new StaticMethodMatcherPointcutAdvisor(overLoadInts) {
1243 @Override
1244 public boolean matches(Method m, Class<?> targetClass) {
1245 return m.getName().equals("overload") && m.getParameterTypes().length == 1 &&
1246 m.getParameterTypes()[0].equals(int.class);
1247 }
1248 });
1249
1250 IOverloads proxy = (IOverloads) createProxy(pc);
1251 assertEquals(0, overLoadInts.getCount());
1252 assertEquals(0, overLoadVoids.getCount());
1253 proxy.overload();
1254 assertEquals(0, overLoadInts.getCount());
1255 assertEquals(1, overLoadVoids.getCount());
1256 assertEquals(25, proxy.overload(25));
1257 assertEquals(1, overLoadInts.getCount());
1258 assertEquals(1, overLoadVoids.getCount());
1259 proxy.noAdvice();
1260 assertEquals(1, overLoadInts.getCount());
1261 assertEquals(1, overLoadVoids.getCount());
1262 }
1263
1264 @Test
1265 public void testProxyIsBoundBeforeTargetSourceInvoked() {
1266 final TestBean target = new TestBean();
1267 ProxyFactory pf = new ProxyFactory(target);
1268 pf.addAdvice(new DebugInterceptor());
1269 pf.setExposeProxy(true);
1270 final ITestBean proxy = (ITestBean) createProxy(pf);
1271 Advised config = (Advised) proxy;
1272
1273 config.setTargetSource(new TargetSource() {
1274 @Override
1275 public Class<?> getTargetClass() {
1276 return TestBean.class;
1277 }
1278
1279 @Override
1280 public boolean isStatic() {
1281 return false;
1282 }
1283
1284 @Override
1285 public Object getTarget() throws Exception {
1286 assertEquals(proxy, AopContext.currentProxy());
1287 return target;
1288 }
1289
1290 @Override
1291 public void releaseTarget(Object target) throws Exception {
1292 }
1293 });
1294
1295
1296 assertEquals(0, proxy.getAge());
1297 }
1298
1299 @Test
1300 public void testEquals() {
1301 IOther a = new AllInstancesAreEqual();
1302 IOther b = new AllInstancesAreEqual();
1303 NopInterceptor i1 = new NopInterceptor();
1304 NopInterceptor i2 = new NopInterceptor();
1305 ProxyFactory pfa = new ProxyFactory(a);
1306 pfa.addAdvice(i1);
1307 ProxyFactory pfb = new ProxyFactory(b);
1308 pfb.addAdvice(i2);
1309 IOther proxyA = (IOther) createProxy(pfa);
1310 IOther proxyB = (IOther) createProxy(pfb);
1311
1312 assertEquals(pfa.getAdvisors().length, pfb.getAdvisors().length);
1313 assertTrue(a.equals(b));
1314 assertTrue(i1.equals(i2));
1315 assertTrue(proxyA.equals(proxyB));
1316 assertEquals(proxyA.hashCode(), proxyB.hashCode());
1317 assertFalse(proxyA.equals(a));
1318
1319
1320 assertEquals(0, i1.getCount());
1321
1322
1323
1324 proxyA.absquatulate();
1325 assertEquals(1, i1.getCount());
1326 assertFalse(proxyA.equals(proxyB));
1327 }
1328
1329 @Test
1330 public void testBeforeAdvisorIsInvoked() {
1331 CountingBeforeAdvice cba = new CountingBeforeAdvice();
1332 @SuppressWarnings("serial")
1333 Advisor matchesNoArgs = new StaticMethodMatcherPointcutAdvisor(cba) {
1334 @Override
1335 public boolean matches(Method m, Class<?> targetClass) {
1336 return m.getParameterTypes().length == 0;
1337 }
1338 };
1339 TestBean target = new TestBean();
1340 target.setAge(80);
1341 ProxyFactory pf = new ProxyFactory(target);
1342 pf.addAdvice(new NopInterceptor());
1343 pf.addAdvisor(matchesNoArgs);
1344 assertEquals("Advisor was added", matchesNoArgs, pf.getAdvisors()[1]);
1345 ITestBean proxied = (ITestBean) createProxy(pf);
1346 assertEquals(0, cba.getCalls());
1347 assertEquals(0, cba.getCalls("getAge"));
1348 assertEquals(target.getAge(), proxied.getAge());
1349 assertEquals(1, cba.getCalls());
1350 assertEquals(1, cba.getCalls("getAge"));
1351 assertEquals(0, cba.getCalls("setAge"));
1352
1353 proxied.setAge(26);
1354 assertEquals(1, cba.getCalls());
1355 assertEquals(26, proxied.getAge());
1356 }
1357
1358 @Test
1359 public void testUserAttributes() throws Throwable {
1360 class MapAwareMethodInterceptor implements MethodInterceptor {
1361 private final Map<String, String> expectedValues;
1362 private final Map<String, String> valuesToAdd;
1363 public MapAwareMethodInterceptor(Map<String, String> expectedValues, Map<String, String> valuesToAdd) {
1364 this.expectedValues = expectedValues;
1365 this.valuesToAdd = valuesToAdd;
1366 }
1367 @Override
1368 public Object invoke(MethodInvocation invocation) throws Throwable {
1369 ReflectiveMethodInvocation rmi = (ReflectiveMethodInvocation) invocation;
1370 for (Iterator<String> it = rmi.getUserAttributes().keySet().iterator(); it.hasNext(); ){
1371 Object key = it.next();
1372 assertEquals(expectedValues.get(key), rmi.getUserAttributes().get(key));
1373 }
1374 rmi.getUserAttributes().putAll(valuesToAdd);
1375 return invocation.proceed();
1376 }
1377 };
1378 AdvisedSupport pc = new AdvisedSupport(new Class<?>[] {ITestBean.class});
1379 MapAwareMethodInterceptor mami1 = new MapAwareMethodInterceptor(new HashMap<String, String>(), new HashMap<String, String>());
1380 Map<String, String> firstValuesToAdd = new HashMap<String, String>();
1381 firstValuesToAdd.put("test", "");
1382 MapAwareMethodInterceptor mami2 = new MapAwareMethodInterceptor(new HashMap<String, String>(), firstValuesToAdd);
1383 MapAwareMethodInterceptor mami3 = new MapAwareMethodInterceptor(firstValuesToAdd, new HashMap<String, String>());
1384 MapAwareMethodInterceptor mami4 = new MapAwareMethodInterceptor(firstValuesToAdd, new HashMap<String, String>());
1385 Map<String, String> secondValuesToAdd = new HashMap<String, String>();
1386 secondValuesToAdd.put("foo", "bar");
1387 secondValuesToAdd.put("cat", "dog");
1388 MapAwareMethodInterceptor mami5 = new MapAwareMethodInterceptor(firstValuesToAdd, secondValuesToAdd);
1389 Map<String, String> finalExpected = new HashMap<String, String>(firstValuesToAdd);
1390 finalExpected.putAll(secondValuesToAdd);
1391 MapAwareMethodInterceptor mami6 = new MapAwareMethodInterceptor(finalExpected, secondValuesToAdd);
1392
1393 pc.addAdvice(mami1);
1394 pc.addAdvice(mami2);
1395 pc.addAdvice(mami3);
1396 pc.addAdvice(mami4);
1397 pc.addAdvice(mami5);
1398 pc.addAdvice(mami6);
1399
1400
1401 pc.setTarget(new TestBean());
1402 AopProxy aop = createAopProxy(pc);
1403 ITestBean tb = (ITestBean) aop.getProxy();
1404
1405 String newName = "foo";
1406 tb.setName(newName);
1407 assertEquals(newName, tb.getName());
1408 }
1409
1410 @Test
1411 public void testMultiAdvice() throws Throwable {
1412 CountingMultiAdvice cca = new CountingMultiAdvice();
1413 @SuppressWarnings("serial")
1414 Advisor matchesNoArgs = new StaticMethodMatcherPointcutAdvisor(cca) {
1415 @Override
1416 public boolean matches(Method m, Class<?> targetClass) {
1417 return m.getParameterTypes().length == 0 || "exceptional".equals(m.getName());
1418 }
1419 };
1420 TestBean target = new TestBean();
1421 target.setAge(80);
1422 ProxyFactory pf = new ProxyFactory(target);
1423 pf.addAdvice(new NopInterceptor());
1424 pf.addAdvisor(matchesNoArgs);
1425 assertEquals("Advisor was added", matchesNoArgs, pf.getAdvisors()[1]);
1426 ITestBean proxied = (ITestBean) createProxy(pf);
1427
1428 assertEquals(0, cca.getCalls());
1429 assertEquals(0, cca.getCalls("getAge"));
1430 assertEquals(target.getAge(), proxied.getAge());
1431 assertEquals(2, cca.getCalls());
1432 assertEquals(2, cca.getCalls("getAge"));
1433 assertEquals(0, cca.getCalls("setAge"));
1434
1435 proxied.setAge(26);
1436 assertEquals(2, cca.getCalls());
1437 assertEquals(26, proxied.getAge());
1438 assertEquals(4, cca.getCalls());
1439 try {
1440 proxied.exceptional(new SpecializedUncheckedException("foo", (SQLException)null));
1441 fail("Should have thrown CannotGetJdbcConnectionException");
1442 }
1443 catch (SpecializedUncheckedException ex) {
1444
1445 }
1446 assertEquals(6, cca.getCalls());
1447 }
1448
1449 @Test
1450 public void testBeforeAdviceThrowsException() {
1451 final RuntimeException rex = new RuntimeException();
1452 @SuppressWarnings("serial")
1453 CountingBeforeAdvice ba = new CountingBeforeAdvice() {
1454 @Override
1455 public void before(Method m, Object[] args, Object target) throws Throwable {
1456 super.before(m, args, target);
1457 if (m.getName().startsWith("set"))
1458 throw rex;
1459 }
1460 };
1461
1462 TestBean target = new TestBean();
1463 target.setAge(80);
1464 NopInterceptor nop1 = new NopInterceptor();
1465 NopInterceptor nop2 = new NopInterceptor();
1466 ProxyFactory pf = new ProxyFactory(target);
1467 pf.addAdvice(nop1);
1468 pf.addAdvice(ba);
1469 pf.addAdvice(nop2);
1470 ITestBean proxied = (ITestBean) createProxy(pf);
1471
1472 assertEquals(target.getAge(), proxied.getAge());
1473 assertEquals(1, ba.getCalls());
1474 assertEquals(1, ba.getCalls("getAge"));
1475 assertEquals(1, nop1.getCount());
1476 assertEquals(1, nop2.getCount());
1477
1478 try {
1479 proxied.setAge(26);
1480 fail("before advice should have ended chain");
1481 }
1482 catch (RuntimeException ex) {
1483 assertEquals(rex, ex);
1484 }
1485 assertEquals(2, ba.getCalls());
1486 assertEquals(2, nop1.getCount());
1487
1488 assertEquals(1, nop2.getCount());
1489
1490 assertEquals(target.getAge(), proxied.getAge());
1491 }
1492
1493
1494 @Test
1495 public void testAfterReturningAdvisorIsInvoked() {
1496 class SummingAfterAdvice implements AfterReturningAdvice {
1497 public int sum;
1498 @Override
1499 public void afterReturning(Object returnValue, Method m, Object[] args, Object target) throws Throwable {
1500 sum += ((Integer) returnValue).intValue();
1501 }
1502 }
1503 SummingAfterAdvice aa = new SummingAfterAdvice();
1504 @SuppressWarnings("serial")
1505 Advisor matchesInt = new StaticMethodMatcherPointcutAdvisor(aa) {
1506 @Override
1507 public boolean matches(Method m, Class<?> targetClass) {
1508 return m.getReturnType() == int.class;
1509 }
1510 };
1511 TestBean target = new TestBean();
1512 ProxyFactory pf = new ProxyFactory(target);
1513 pf.addAdvice(new NopInterceptor());
1514 pf.addAdvisor(matchesInt);
1515 assertEquals("Advisor was added", matchesInt, pf.getAdvisors()[1]);
1516 ITestBean proxied = (ITestBean) createProxy(pf);
1517 assertEquals(0, aa.sum);
1518 int i1 = 12;
1519 int i2 = 13;
1520
1521
1522 proxied.setAge(i1);
1523 assertEquals(i1, proxied.getAge());
1524 assertEquals(i1, aa.sum);
1525 proxied.setAge(i2);
1526 assertEquals(i2, proxied.getAge());
1527 assertEquals(i1 + i2, aa.sum);
1528 assertEquals(i2, proxied.getAge());
1529 }
1530
1531 @Test
1532 public void testAfterReturningAdvisorIsNotInvokedOnException() {
1533 CountingAfterReturningAdvice car = new CountingAfterReturningAdvice();
1534 TestBean target = new TestBean();
1535 ProxyFactory pf = new ProxyFactory(target);
1536 pf.addAdvice(new NopInterceptor());
1537 pf.addAdvice(car);
1538 assertEquals("Advice was wrapped in Advisor and added", car, pf.getAdvisors()[1].getAdvice());
1539 ITestBean proxied = (ITestBean) createProxy(pf);
1540 assertEquals(0, car.getCalls());
1541 int age = 10;
1542 proxied.setAge(age);
1543 assertEquals(age, proxied.getAge());
1544 assertEquals(2, car.getCalls());
1545 Exception exc = new Exception();
1546
1547 try {
1548 proxied.exceptional(exc);
1549 fail();
1550 }
1551 catch (Throwable t) {
1552 assertSame(exc, t);
1553 }
1554 assertEquals(2, car.getCalls());
1555 }
1556
1557
1558 @Test
1559 public void testThrowsAdvisorIsInvoked() throws Throwable {
1560
1561 MyThrowsHandler th = new MyThrowsHandler();
1562 @SuppressWarnings("serial")
1563 Advisor matchesEchoInvocations = new StaticMethodMatcherPointcutAdvisor(th) {
1564 @Override
1565 public boolean matches(Method m, Class<?> targetClass) {
1566 return m.getName().startsWith("echo");
1567 }
1568 };
1569
1570 Echo target = new Echo();
1571 target.setA(16);
1572 ProxyFactory pf = new ProxyFactory(target);
1573 pf.addAdvice(new NopInterceptor());
1574 pf.addAdvisor(matchesEchoInvocations);
1575 assertEquals("Advisor was added", matchesEchoInvocations, pf.getAdvisors()[1]);
1576 IEcho proxied = (IEcho) createProxy(pf);
1577 assertEquals(0, th.getCalls());
1578 assertEquals(target.getA(), proxied.getA());
1579 assertEquals(0, th.getCalls());
1580 Exception ex = new Exception();
1581
1582 try {
1583 proxied.echoException(1, ex);
1584 fail();
1585 }
1586 catch (Exception caught) {
1587 assertEquals(ex, caught);
1588 }
1589
1590 ex = new FileNotFoundException();
1591 try {
1592 proxied.echoException(1, ex);
1593 fail();
1594 }
1595 catch (FileNotFoundException caught) {
1596 assertEquals(ex, caught);
1597 }
1598 assertEquals(1, th.getCalls("ioException"));
1599 }
1600
1601 @Test
1602 public void testAddThrowsAdviceWithoutAdvisor() throws Throwable {
1603
1604 MyThrowsHandler th = new MyThrowsHandler();
1605
1606 Echo target = new Echo();
1607 target.setA(16);
1608 ProxyFactory pf = new ProxyFactory(target);
1609 pf.addAdvice(new NopInterceptor());
1610 pf.addAdvice(th);
1611 IEcho proxied = (IEcho) createProxy(pf);
1612 assertEquals(0, th.getCalls());
1613 assertEquals(target.getA(), proxied.getA());
1614 assertEquals(0, th.getCalls());
1615 Exception ex = new Exception();
1616
1617 try {
1618 proxied.echoException(1, ex);
1619 fail();
1620 }
1621 catch (Exception caught) {
1622 assertEquals(ex, caught);
1623 }
1624
1625
1626 ex = new MarshalException("");
1627 try {
1628 proxied.echoException(1, ex);
1629 fail();
1630 }
1631 catch (MarshalException caught) {
1632 assertEquals(ex, caught);
1633 }
1634 assertEquals(1, th.getCalls("remoteException"));
1635 }
1636
1637 private static class CheckMethodInvocationIsSameInAndOutInterceptor implements MethodInterceptor {
1638
1639 @Override
1640 public Object invoke(MethodInvocation mi) throws Throwable {
1641 Method m = mi.getMethod();
1642 Object retval = mi.proceed();
1643 assertEquals("Method invocation has same method on way back", m, mi.getMethod());
1644 return retval;
1645 }
1646 }
1647
1648
1649
1650
1651
1652 private static class CheckMethodInvocationViaThreadLocalIsSameInAndOutInterceptor implements MethodInterceptor {
1653
1654 @Override
1655 public Object invoke(MethodInvocation mi) throws Throwable {
1656 String task = "get invocation on way IN";
1657 try {
1658 MethodInvocation current = ExposeInvocationInterceptor.currentInvocation();
1659 assertEquals(mi.getMethod(), current.getMethod());
1660 Object retval = mi.proceed();
1661 task = "get invocation on way OUT";
1662 assertEquals(current, ExposeInvocationInterceptor.currentInvocation());
1663 return retval;
1664 }
1665 catch (IllegalStateException ex) {
1666 System.err.println(task + " for " + mi.getMethod());
1667 ex.printStackTrace();
1668 throw ex;
1669 }
1670 }
1671 }
1672
1673
1674
1675
1676
1677
1678
1679 private static class ProxyMatcherInterceptor implements MethodInterceptor {
1680
1681 @Override
1682 public Object invoke(MethodInvocation mi) throws Throwable {
1683 Object proxy = AopContext.currentProxy();
1684 Object ret = mi.proceed();
1685
1686
1687 assertTrue(proxy == AopContext.currentProxy());
1688 return ret;
1689 }
1690 }
1691
1692
1693
1694
1695
1696 @SuppressWarnings("serial")
1697 protected static class StringSetterNullReplacementAdvice extends DefaultPointcutAdvisor {
1698
1699 private static MethodInterceptor cleaner = new MethodInterceptor() {
1700 @Override
1701 public Object invoke(MethodInvocation mi) throws Throwable {
1702
1703 mi.getArguments()[0] = "";
1704 return mi.proceed();
1705 }
1706 };
1707
1708 public StringSetterNullReplacementAdvice() {
1709 super(cleaner);
1710 setPointcut(new DynamicMethodMatcherPointcut() {
1711 @Override
1712 public boolean matches(Method m, Class<?> targetClass, Object[] args) {
1713 return args[0] == null;
1714 }
1715 @Override
1716 public boolean matches(Method m, Class<?> targetClass) {
1717 return m.getName().startsWith("set") &&
1718 m.getParameterTypes().length == 1 &&
1719 m.getParameterTypes()[0].equals(String.class);
1720 }
1721 });
1722 }
1723 }
1724
1725
1726 @SuppressWarnings("serial")
1727 protected static class TestDynamicPointcutAdvice extends DefaultPointcutAdvisor {
1728
1729 public int count;
1730
1731 public TestDynamicPointcutAdvice(MethodInterceptor mi, final String pattern) {
1732 super(mi);
1733 setPointcut(new DynamicMethodMatcherPointcut() {
1734 @Override
1735 public boolean matches(Method m, Class<?> targetClass, Object[] args) {
1736 boolean run = m.getName().indexOf(pattern) != -1;
1737 if (run) ++count;
1738 return run;
1739 }
1740 });
1741 }
1742 }
1743
1744
1745 @SuppressWarnings("serial")
1746 protected static class TestDynamicPointcutForSettersOnly extends DefaultPointcutAdvisor {
1747
1748 public int count;
1749
1750 public TestDynamicPointcutForSettersOnly(MethodInterceptor mi, final String pattern) {
1751 super(mi);
1752 setPointcut(new DynamicMethodMatcherPointcut() {
1753 @Override
1754 public boolean matches(Method m, Class<?> targetClass, Object[] args) {
1755 boolean run = m.getName().indexOf(pattern) != -1;
1756 if (run) ++count;
1757 return run;
1758 }
1759 @Override
1760 public boolean matches(Method m, Class<?> clazz) {
1761 return m.getName().startsWith("set");
1762 }
1763 });
1764 }
1765 }
1766
1767
1768 @SuppressWarnings("serial")
1769 protected static class TestStaticPointcutAdvice extends StaticMethodMatcherPointcutAdvisor {
1770
1771 private String pattern;
1772
1773 public TestStaticPointcutAdvice(MethodInterceptor mi, String pattern) {
1774 super(mi);
1775 this.pattern = pattern;
1776 }
1777 @Override
1778 public boolean matches(Method m, Class<?> targetClass) {
1779 return m.getName().indexOf(pattern) != -1;
1780 }
1781 }
1782
1783
1784
1785
1786
1787
1788
1789
1790 protected static class TrapTargetInterceptor implements MethodInterceptor {
1791
1792 public Object target;
1793
1794 @Override
1795 public Object invoke(MethodInvocation invocation) throws Throwable {
1796 this.target = invocation.getThis();
1797 return invocation.proceed();
1798 }
1799 }
1800
1801
1802 private static class DummyIntroductionAdviceImpl implements DynamicIntroductionAdvice {
1803
1804 @Override
1805 public boolean implementsInterface(Class<?> intf) {
1806 return true;
1807 }
1808 }
1809
1810
1811 public static class OwnSpouse extends TestBean {
1812
1813 @Override
1814 public ITestBean getSpouse() {
1815 return this;
1816 }
1817 }
1818
1819
1820 public static class AllInstancesAreEqual implements IOther {
1821
1822 @Override
1823 public boolean equals(Object other) {
1824 return (other instanceof AllInstancesAreEqual);
1825 }
1826
1827 @Override
1828 public int hashCode() {
1829 return getClass().hashCode();
1830 }
1831
1832 @Override
1833 public void absquatulate() {
1834 }
1835 }
1836
1837
1838 public interface INeedsToSeeProxy {
1839
1840 int getCount();
1841
1842 void incrementViaThis();
1843
1844 void incrementViaProxy();
1845
1846 void increment();
1847 }
1848
1849
1850 public static class NeedsToSeeProxy implements INeedsToSeeProxy {
1851
1852 private int count;
1853
1854 @Override
1855 public int getCount() {
1856 return count;
1857 }
1858
1859 @Override
1860 public void incrementViaThis() {
1861 this.increment();
1862 }
1863
1864 @Override
1865 public void incrementViaProxy() {
1866 INeedsToSeeProxy thisViaProxy = (INeedsToSeeProxy) AopContext.currentProxy();
1867 thisViaProxy.increment();
1868 Advised advised = (Advised) thisViaProxy;
1869 checkAdvised(advised);
1870 }
1871
1872 protected void checkAdvised(Advised advised) {
1873 }
1874
1875 @Override
1876 public void increment() {
1877 ++count;
1878 }
1879 }
1880
1881
1882 public static class TargetChecker extends NeedsToSeeProxy {
1883
1884 @Override
1885 protected void checkAdvised(Advised advised) {
1886
1887
1888 }
1889 }
1890
1891
1892 public static class CountingAdvisorListener implements AdvisedSupportListener {
1893
1894 public int adviceChanges;
1895 public int activates;
1896 private AdvisedSupport expectedSource;
1897
1898 public CountingAdvisorListener(AdvisedSupport expectedSource) {
1899 this.expectedSource = expectedSource;
1900 }
1901
1902 @Override
1903 public void activated(AdvisedSupport advised) {
1904 assertEquals(expectedSource, advised);
1905 ++activates;
1906 }
1907
1908 @Override
1909 public void adviceChanged(AdvisedSupport advised) {
1910 assertEquals(expectedSource, advised);
1911 ++adviceChanges;
1912 }
1913 }
1914
1915
1916 public static class RefreshCountingAdvisorChainFactory implements AdvisedSupportListener {
1917
1918 public int refreshes;
1919
1920 @Override
1921 public void activated(AdvisedSupport advised) {
1922 ++refreshes;
1923 }
1924
1925 @Override
1926 public void adviceChanged(AdvisedSupport advised) {
1927 ++refreshes;
1928 }
1929 }
1930
1931
1932 public static interface IOverloads {
1933
1934 void overload();
1935
1936 int overload(int i);
1937
1938 String overload(String foo);
1939
1940 void noAdvice();
1941 }
1942
1943
1944 public static class Overloads implements IOverloads {
1945
1946 @Override
1947 public void overload() {
1948 }
1949
1950 @Override
1951 public int overload(int i) {
1952 return i;
1953 }
1954
1955 @Override
1956 public String overload(String s) {
1957 return s;
1958 }
1959
1960 @Override
1961 public void noAdvice() {
1962 }
1963 }
1964
1965
1966 @SuppressWarnings("serial")
1967 public static class CountingMultiAdvice extends MethodCounter implements MethodBeforeAdvice,
1968 AfterReturningAdvice, ThrowsAdvice {
1969
1970 @Override
1971 public void before(Method m, Object[] args, Object target) throws Throwable {
1972 count(m);
1973 }
1974
1975 @Override
1976 public void afterReturning(Object o, Method m, Object[] args, Object target)
1977 throws Throwable {
1978 count(m);
1979 }
1980
1981 public void afterThrowing(IOException ex) throws Throwable {
1982 count(IOException.class.getName());
1983 }
1984
1985 public void afterThrowing(UncheckedException ex) throws Throwable {
1986 count(UncheckedException.class.getName());
1987 }
1988
1989 }
1990
1991
1992 @SuppressWarnings("serial")
1993 public static class CountingThrowsAdvice extends MethodCounter implements ThrowsAdvice {
1994
1995 public void afterThrowing(IOException ex) throws Throwable {
1996 count(IOException.class.getName());
1997 }
1998
1999 public void afterThrowing(UncheckedException ex) throws Throwable {
2000 count(UncheckedException.class.getName());
2001 }
2002
2003 }
2004
2005
2006 @SuppressWarnings("serial")
2007 static class UncheckedException extends RuntimeException {
2008
2009 }
2010
2011
2012 @SuppressWarnings("serial")
2013 static class SpecializedUncheckedException extends UncheckedException {
2014
2015 public SpecializedUncheckedException(String string, SQLException exception) {
2016 }
2017
2018 }
2019
2020
2021 static class MockTargetSource implements TargetSource {
2022
2023 private Object target;
2024
2025 public int gets;
2026
2027 public int releases;
2028
2029 public void reset() {
2030 this.target = null;
2031 gets = releases = 0;
2032 }
2033
2034 public void setTarget(Object target) {
2035 this.target = target;
2036 }
2037
2038
2039
2040
2041 @Override
2042 public Class<?> getTargetClass() {
2043 return target.getClass();
2044 }
2045
2046
2047
2048
2049 @Override
2050 public Object getTarget() throws Exception {
2051 ++gets;
2052 return target;
2053 }
2054
2055
2056
2057
2058 @Override
2059 public void releaseTarget(Object pTarget) throws Exception {
2060 if (pTarget != this.target)
2061 throw new RuntimeException("Released wrong target");
2062 ++releases;
2063 }
2064
2065
2066
2067
2068
2069 public void verify() {
2070 if (gets != releases)
2071 throw new RuntimeException("Expectation failed: " + gets + " gets and " + releases + " releases");
2072 }
2073
2074
2075
2076
2077 @Override
2078 public boolean isStatic() {
2079 return false;
2080 }
2081
2082 }
2083
2084
2085 static abstract class ExposedInvocationTestBean extends TestBean {
2086
2087 @Override
2088 public String getName() {
2089 MethodInvocation invocation = ExposeInvocationInterceptor.currentInvocation();
2090 assertions(invocation);
2091 return super.getName();
2092 }
2093
2094 @Override
2095 public void absquatulate() {
2096 MethodInvocation invocation = ExposeInvocationInterceptor.currentInvocation();
2097 assertions(invocation);
2098 super.absquatulate();
2099 }
2100
2101 protected abstract void assertions(MethodInvocation invocation);
2102 }
2103
2104
2105 static class InvocationCheckExposedInvocationTestBean extends ExposedInvocationTestBean {
2106 @Override
2107 protected void assertions(MethodInvocation invocation) {
2108 TestCase.assertTrue(invocation.getThis() == this);
2109 TestCase.assertTrue("Invocation should be on ITestBean: " + invocation.getMethod(),
2110 ITestBean.class.isAssignableFrom(invocation.getMethod().getDeclaringClass()));
2111 }
2112 }
2113
2114 }
2115