View Javadoc
1   /*
2    * Copyright 2002-2014 the original author or authors.
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    *      http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  package org.springframework.aop.aspectj.annotation;
17  
18  import java.io.FileNotFoundException;
19  import java.lang.annotation.Retention;
20  import java.lang.annotation.RetentionPolicy;
21  import java.lang.reflect.Method;
22  import java.lang.reflect.UndeclaredThrowableException;
23  import java.rmi.RemoteException;
24  import java.util.Collections;
25  import java.util.LinkedList;
26  import java.util.List;
27  
28  import org.aspectj.lang.JoinPoint;
29  import org.aspectj.lang.ProceedingJoinPoint;
30  import org.aspectj.lang.annotation.After;
31  import org.aspectj.lang.annotation.AfterReturning;
32  import org.aspectj.lang.annotation.AfterThrowing;
33  import org.aspectj.lang.annotation.Around;
34  import org.aspectj.lang.annotation.Aspect;
35  import org.aspectj.lang.annotation.Before;
36  import org.aspectj.lang.annotation.DeclareParents;
37  import org.aspectj.lang.annotation.DeclarePrecedence;
38  import org.aspectj.lang.annotation.Pointcut;
39  import org.aspectj.lang.reflect.MethodSignature;
40  import org.junit.Ignore;
41  import org.junit.Test;
42  import test.aop.DefaultLockable;
43  import test.aop.Lockable;
44  import test.aop.PerTargetAspect;
45  import test.aop.TwoAdviceAspect;
46  
47  import org.springframework.aop.Advisor;
48  import org.springframework.aop.aspectj.annotation.ReflectiveAspectJAdvisorFactory.SyntheticInstantiationAdvisor;
49  import org.springframework.aop.framework.Advised;
50  import org.springframework.aop.framework.AopConfigException;
51  import org.springframework.aop.framework.ProxyFactory;
52  import org.springframework.aop.interceptor.ExposeInvocationInterceptor;
53  import org.springframework.aop.support.AopUtils;
54  import org.springframework.core.OrderComparator;
55  import org.springframework.core.Ordered;
56  import org.springframework.core.annotation.Order;
57  import org.springframework.tests.sample.beans.ITestBean;
58  import org.springframework.tests.sample.beans.TestBean;
59  import org.springframework.util.ObjectUtils;
60  
61  import static org.hamcrest.Matchers.*;
62  import static org.junit.Assert.*;
63  
64  /**
65   * Abstract tests for AspectJAdvisorFactory.
66   * See subclasses for tests of concrete factories.
67   *
68   * @author Rod Johnson
69   * @author Chris Beams
70   * @author Phillip Webb
71   */
72  public abstract class AbstractAspectJAdvisorFactoryTests {
73  
74  	/**
75  	 * To be overridden by concrete test subclasses.
76  	 * @return the fixture
77  	 */
78  	protected abstract AspectJAdvisorFactory getFixture();
79  
80  
81  	@Test
82  	public void testRejectsPerCflowAspect() {
83  		try {
84  			getFixture().getAdvisors(new SingletonMetadataAwareAspectInstanceFactory(new PerCflowAspect(),"someBean"));
85  			fail("Cannot accept cflow");
86  		}
87  		catch (AopConfigException ex) {
88  			assertTrue(ex.getMessage().indexOf("PERCFLOW") != -1);
89  		}
90  	}
91  
92  	@Test
93  	public void testRejectsPerCflowBelowAspect() {
94  		try {
95  			getFixture().getAdvisors(new SingletonMetadataAwareAspectInstanceFactory(new PerCflowBelowAspect(),"someBean"));
96  			fail("Cannot accept cflowbelow");
97  		}
98  		catch (AopConfigException ex) {
99  			assertTrue(ex.getMessage().indexOf("PERCFLOWBELOW") != -1);
100 		}
101 	}
102 
103 	@Test
104 	public void testPerTargetAspect() throws SecurityException, NoSuchMethodException {
105 		TestBean target = new TestBean();
106 		int realAge = 65;
107 		target.setAge(realAge);
108 		TestBean itb = (TestBean) createProxy(target,
109 				getFixture().getAdvisors(new SingletonMetadataAwareAspectInstanceFactory(new PerTargetAspect(), "someBean")),
110 				TestBean.class);
111 		assertEquals("Around advice must NOT apply", realAge, itb.getAge());
112 
113 		Advised advised = (Advised) itb;
114 		SyntheticInstantiationAdvisor sia = (SyntheticInstantiationAdvisor) advised.getAdvisors()[1];
115 		assertTrue(sia.getPointcut().getMethodMatcher().matches(TestBean.class.getMethod("getSpouse"), null));
116 		InstantiationModelAwarePointcutAdvisorImpl imapa = (InstantiationModelAwarePointcutAdvisorImpl) advised.getAdvisors()[3];
117 		LazySingletonAspectInstanceFactoryDecorator maaif =
118 				(LazySingletonAspectInstanceFactoryDecorator) imapa.getAspectInstanceFactory();
119 		assertFalse(maaif.isMaterialized());
120 
121 		// Check that the perclause pointcut is valid
122 		assertTrue(maaif.getAspectMetadata().getPerClausePointcut().getMethodMatcher().matches(TestBean.class.getMethod("getSpouse"), null));
123 		assertNotSame(imapa.getDeclaredPointcut(), imapa.getPointcut());
124 
125 		// Hit the method in the per clause to instantiate the aspect
126 		itb.getSpouse();
127 
128 		assertTrue(maaif.isMaterialized());
129 
130 		assertEquals("Around advice must apply", 0, itb.getAge());
131 		assertEquals("Around advice must apply", 1, itb.getAge());
132 	}
133 
134 	@Test
135 	public void testMultiplePerTargetAspects() throws SecurityException, NoSuchMethodException {
136 		TestBean target = new TestBean();
137 		int realAge = 65;
138 		target.setAge(realAge);
139 
140 		List<Advisor> advisors = new LinkedList<Advisor>();
141 		PerTargetAspect aspect1 = new PerTargetAspect();
142 		aspect1.count = 100;
143 		aspect1.setOrder(10);
144 		advisors.addAll(
145 				getFixture().getAdvisors(new SingletonMetadataAwareAspectInstanceFactory(aspect1, "someBean1")));
146 		PerTargetAspect aspect2 = new PerTargetAspect();
147 		aspect2.setOrder(5);
148 		advisors.addAll(
149 				getFixture().getAdvisors(new SingletonMetadataAwareAspectInstanceFactory(aspect2, "someBean2")));
150 		Collections.sort(advisors, new OrderComparator());
151 
152 		TestBean itb = (TestBean) createProxy(target, advisors, TestBean.class);
153 		assertEquals("Around advice must NOT apply", realAge, itb.getAge());
154 
155 		// Hit the method in the per clause to instantiate the aspect
156 		itb.getSpouse();
157 
158 		assertEquals("Around advice must apply", 0, itb.getAge());
159 		assertEquals("Around advice must apply", 1, itb.getAge());
160 	}
161 
162 	@Test
163 	public void testMultiplePerTargetAspectsWithOrderAnnotation() throws SecurityException, NoSuchMethodException {
164 		TestBean target = new TestBean();
165 		int realAge = 65;
166 		target.setAge(realAge);
167 
168 		List<Advisor> advisors = new LinkedList<Advisor>();
169 		PerTargetAspectWithOrderAnnotation10 aspect1 = new PerTargetAspectWithOrderAnnotation10();
170 		aspect1.count = 100;
171 		advisors.addAll(
172 				getFixture().getAdvisors(new SingletonMetadataAwareAspectInstanceFactory(aspect1, "someBean1")));
173 		PerTargetAspectWithOrderAnnotation5 aspect2 = new PerTargetAspectWithOrderAnnotation5();
174 		advisors.addAll(
175 				getFixture().getAdvisors(new SingletonMetadataAwareAspectInstanceFactory(aspect2, "someBean2")));
176 		Collections.sort(advisors, new OrderComparator());
177 
178 		TestBean itb = (TestBean) createProxy(target, advisors, TestBean.class);
179 		assertEquals("Around advice must NOT apply", realAge, itb.getAge());
180 
181 		// Hit the method in the per clause to instantiate the aspect
182 		itb.getSpouse();
183 
184 		assertEquals("Around advice must apply", 0, itb.getAge());
185 		assertEquals("Around advice must apply", 1, itb.getAge());
186 	}
187 
188 	@Test
189 	public void testPerThisAspect() throws SecurityException, NoSuchMethodException {
190 		TestBean target = new TestBean();
191 		int realAge = 65;
192 		target.setAge(realAge);
193 		TestBean itb = (TestBean) createProxy(target,
194 				getFixture().getAdvisors(new SingletonMetadataAwareAspectInstanceFactory(new PerThisAspect(), "someBean")),
195 				TestBean.class);
196 		assertEquals("Around advice must NOT apply", realAge, itb.getAge());
197 
198 		Advised advised = (Advised) itb;
199 		// Will be ExposeInvocationInterceptor, synthetic instantiation advisor, 2 method advisors
200 		assertEquals(4, advised.getAdvisors().length);
201 		SyntheticInstantiationAdvisor sia = (SyntheticInstantiationAdvisor) advised.getAdvisors()[1];
202 		assertTrue(sia.getPointcut().getMethodMatcher().matches(TestBean.class.getMethod("getSpouse"), null));
203 		InstantiationModelAwarePointcutAdvisorImpl imapa = (InstantiationModelAwarePointcutAdvisorImpl) advised.getAdvisors()[2];
204 		LazySingletonAspectInstanceFactoryDecorator maaif =
205 				(LazySingletonAspectInstanceFactoryDecorator) imapa.getAspectInstanceFactory();
206 		assertFalse(maaif.isMaterialized());
207 
208 		// Check that the perclause pointcut is valid
209 		assertTrue(maaif.getAspectMetadata().getPerClausePointcut().getMethodMatcher().matches(TestBean.class.getMethod("getSpouse"), null));
210 		assertNotSame(imapa.getDeclaredPointcut(), imapa.getPointcut());
211 
212 		// Hit the method in the per clause to instantiate the aspect
213 		itb.getSpouse();
214 
215 		assertTrue(maaif.isMaterialized());
216 
217 		assertTrue(imapa.getDeclaredPointcut().getMethodMatcher().matches(TestBean.class.getMethod("getAge"), null));
218 
219 		assertEquals("Around advice must apply", 0, itb.getAge());
220 		assertEquals("Around advice must apply", 1, itb.getAge());
221 	}
222 
223 	@Test
224 	public void testPerTypeWithinAspect() throws SecurityException, NoSuchMethodException {
225 		TestBean target = new TestBean();
226 		int realAge = 65;
227 		target.setAge(realAge);
228 		PerTypeWithinAspectInstanceFactory aif = new PerTypeWithinAspectInstanceFactory();
229 		TestBean itb = (TestBean) createProxy(target,
230 				getFixture().getAdvisors(aif),
231 				TestBean.class);
232 		assertEquals("No method calls", 0, aif.getInstantiationCount());
233 		assertEquals("Around advice must now apply", 0, itb.getAge());
234 
235 		Advised advised = (Advised) itb;
236 		// Will be ExposeInvocationInterceptor, synthetic instantiation advisor, 2 method advisors
237 		assertEquals(4, advised.getAdvisors().length);
238 		SyntheticInstantiationAdvisor sia = (SyntheticInstantiationAdvisor) advised.getAdvisors()[1];
239 		assertTrue(sia.getPointcut().getMethodMatcher().matches(TestBean.class.getMethod("getSpouse"), null));
240 		InstantiationModelAwarePointcutAdvisorImpl imapa = (InstantiationModelAwarePointcutAdvisorImpl) advised.getAdvisors()[2];
241 		LazySingletonAspectInstanceFactoryDecorator maaif =
242 				(LazySingletonAspectInstanceFactoryDecorator) imapa.getAspectInstanceFactory();
243 		assertTrue(maaif.isMaterialized());
244 
245 		// Check that the perclause pointcut is valid
246 		assertTrue(maaif.getAspectMetadata().getPerClausePointcut().getMethodMatcher().matches(TestBean.class.getMethod("getSpouse"), null));
247 		assertNotSame(imapa.getDeclaredPointcut(), imapa.getPointcut());
248 
249 		// Hit the method in the per clause to instantiate the aspect
250 		itb.getSpouse();
251 
252 		assertTrue(maaif.isMaterialized());
253 
254 		assertTrue(imapa.getDeclaredPointcut().getMethodMatcher().matches(TestBean.class.getMethod("getAge"), null));
255 
256 		assertEquals("Around advice must still apply", 1, itb.getAge());
257 		assertEquals("Around advice must still apply", 2, itb.getAge());
258 
259 		TestBean itb2 = (TestBean) createProxy(target,
260 				getFixture().getAdvisors(aif),
261 				TestBean.class);
262 		assertEquals(1, aif.getInstantiationCount());
263 		assertEquals("Around advice be independent for second instance", 0, itb2.getAge());
264 		assertEquals(2, aif.getInstantiationCount());
265 	}
266 
267 	@Test
268 	public void testNamedPointcutAspectWithFQN() {
269 		testNamedPointcuts(new NamedPointcutAspectWithFQN());
270 	}
271 
272 	@Test
273 	public void testNamedPointcutAspectWithoutFQN() {
274 		testNamedPointcuts(new NamedPointcutAspectWithoutFQN());
275 	}
276 
277 	@Test
278 	public void testNamedPointcutFromAspectLibrary() {
279 		testNamedPointcuts(new NamedPointcutAspectFromLibrary());
280 	}
281 
282 	@Test
283 	public void testNamedPointcutFromAspectLibraryWithBinding() {
284 		TestBean target = new TestBean();
285 		ITestBean itb = (ITestBean) createProxy(target,
286 				getFixture().getAdvisors(new SingletonMetadataAwareAspectInstanceFactory(new NamedPointcutAspectFromLibraryWithBinding(),"someBean")),
287 				ITestBean.class);
288 		itb.setAge(10);
289 		assertEquals("Around advice must apply", 20, itb.getAge());
290 		assertEquals(20,target.getAge());
291 	}
292 
293 	private void testNamedPointcuts(Object aspectInstance) {
294 		TestBean target = new TestBean();
295 		int realAge = 65;
296 		target.setAge(realAge);
297 		ITestBean itb = (ITestBean) createProxy(target,
298 				getFixture().getAdvisors(new SingletonMetadataAwareAspectInstanceFactory(aspectInstance,"someBean")),
299 				ITestBean.class);
300 		assertEquals("Around advice must apply", -1, itb.getAge());
301 		assertEquals(realAge, target.getAge());
302 	}
303 
304 	@Test
305 	public void testBindingWithSingleArg() {
306 		TestBean target = new TestBean();
307 		ITestBean itb = (ITestBean) createProxy(target,
308 				getFixture().getAdvisors(new SingletonMetadataAwareAspectInstanceFactory(new BindingAspectWithSingleArg(),"someBean")),
309 				ITestBean.class);
310 		itb.setAge(10);
311 		assertEquals("Around advice must apply", 20, itb.getAge());
312 		assertEquals(20,target.getAge());
313 	}
314 
315 	@Test
316 	public void testBindingWithMultipleArgsDifferentlyOrdered() {
317 		ManyValuedArgs target = new ManyValuedArgs();
318 		ManyValuedArgs mva = (ManyValuedArgs) createProxy(target,
319 				getFixture().getAdvisors(new SingletonMetadataAwareAspectInstanceFactory(new ManyValuedArgs(),"someBean")),
320 				ManyValuedArgs.class);
321 
322 		String a = "a";
323 		int b = 12;
324 		int c = 25;
325 		String d = "d";
326 		StringBuffer e = new StringBuffer("stringbuf");
327 		String expectedResult = a + b+ c + d + e;
328 		assertEquals(expectedResult, mva.mungeArgs(a, b, c, d, e));
329 	}
330 
331 	/**
332 	 * In this case the introduction will be made.
333 	 */
334 	@Test
335 	public void testIntroductionOnTargetNotImplementingInterface() {
336 		NotLockable notLockableTarget = new NotLockable();
337 		assertFalse(notLockableTarget instanceof Lockable);
338 		NotLockable notLockable1 = (NotLockable) createProxy(notLockableTarget,
339 				getFixture().getAdvisors(
340 						new SingletonMetadataAwareAspectInstanceFactory(new MakeLockable(),"someBean")),
341 				NotLockable.class);
342 		assertTrue(notLockable1 instanceof Lockable);
343 		Lockable lockable = (Lockable) notLockable1;
344 		assertFalse(lockable.locked());
345 		lockable.lock();
346 		assertTrue(lockable.locked());
347 
348 		NotLockable notLockable2Target = new NotLockable();
349 		NotLockable notLockable2 = (NotLockable) createProxy(notLockable2Target,
350 				getFixture().getAdvisors(
351 						new SingletonMetadataAwareAspectInstanceFactory(new MakeLockable(),"someBean")),
352 				NotLockable.class);
353 		assertTrue(notLockable2 instanceof Lockable);
354 		Lockable lockable2 = (Lockable) notLockable2;
355 		assertFalse(lockable2.locked());
356 		notLockable2.setIntValue(1);
357 		lockable2.lock();
358 		try {
359 			notLockable2.setIntValue(32);
360 			fail();
361 		}
362 		catch (IllegalStateException ex) {
363 		}
364 		assertTrue(lockable2.locked());
365 	}
366 
367 	@Test
368 	public void testIntroductionAdvisorExcludedFromTargetImplementingInterface() {
369 		assertTrue(AopUtils.findAdvisorsThatCanApply(
370 						getFixture().getAdvisors(
371 									new SingletonMetadataAwareAspectInstanceFactory(
372 											new MakeLockable(),"someBean")),
373 						CannotBeUnlocked.class).isEmpty());
374 		assertEquals(2, AopUtils.findAdvisorsThatCanApply(getFixture().getAdvisors(new SingletonMetadataAwareAspectInstanceFactory(new MakeLockable(),"someBean")), NotLockable.class).size());
375 	}
376 
377 	@Test
378 	public void testIntroductionOnTargetImplementingInterface() {
379 		CannotBeUnlocked target = new CannotBeUnlocked();
380 		Lockable proxy = (Lockable) createProxy(target,
381 				// Ensure that we exclude
382 				AopUtils.findAdvisorsThatCanApply(
383 						getFixture().getAdvisors(
384 								new SingletonMetadataAwareAspectInstanceFactory(new MakeLockable(), "someBean")),
385 						CannotBeUnlocked.class
386 				),
387 				CannotBeUnlocked.class);
388 		assertThat(proxy, instanceOf(Lockable.class));
389 		Lockable lockable = proxy;
390 		assertTrue("Already locked", lockable.locked());
391 		lockable.lock();
392 		assertTrue("Real target ignores locking", lockable.locked());
393 		try {
394 			lockable.unlock();
395 			fail();
396 		}
397 		catch (UnsupportedOperationException ex) {
398 			// Ok
399 		}
400 	}
401 
402 	@Test
403 	public void testIntroductionOnTargetExcludedByTypePattern() {
404 		LinkedList<Object> target = new LinkedList<Object>();
405 		List<?> proxy = (List<?>) createProxy(target,
406 				AopUtils.findAdvisorsThatCanApply(
407 						getFixture().getAdvisors(new SingletonMetadataAwareAspectInstanceFactory(new MakeLockable(), "someBean")),
408 						List.class
409 				),
410 				CannotBeUnlocked.class);
411 		assertFalse("Type pattern must have excluded mixin", proxy instanceof Lockable);
412 	}
413 
414 	/* prereq AspectJ 1.6.7
415 	@Test
416 	public void testIntroductionBasedOnAnnotationMatch_Spr5307() {
417 		AnnotatedTarget target = new AnnotatedTargetImpl();
418 
419 		List<Advisor> advisors = getFixture().getAdvisors(
420 				new SingletonMetadataAwareAspectInstanceFactory(new MakeAnnotatedTypeModifiable(),"someBean"));
421 		Object proxy = createProxy(target,
422 				advisors,
423 				AnnotatedTarget.class);
424 		System.out.println(advisors.get(1));
425 		assertTrue(proxy instanceof Lockable);
426 		Lockable lockable = (Lockable)proxy;
427 		lockable.locked();
428 	}
429 	*/
430 
431 	// TODO: Why does this test fail? It hasn't been run before, so it maybe never actually passed...
432 
433 	@Test
434 	@Ignore
435 	public void testIntroductionWithArgumentBinding() {
436 		TestBean target = new TestBean();
437 
438 		List<Advisor> advisors = getFixture().getAdvisors(
439 				new SingletonMetadataAwareAspectInstanceFactory(new MakeITestBeanModifiable(),"someBean"));
440 		advisors.addAll(getFixture().getAdvisors(
441 				new SingletonMetadataAwareAspectInstanceFactory(new MakeLockable(),"someBean")));
442 
443 		Modifiable modifiable = (Modifiable) createProxy(target,
444 				advisors,
445 				ITestBean.class);
446 		assertThat(modifiable, instanceOf(Modifiable.class));
447 		Lockable lockable = (Lockable) modifiable;
448 		assertFalse(lockable.locked());
449 
450 		ITestBean itb = (ITestBean) modifiable;
451 		assertFalse(modifiable.isModified());
452 		int oldAge = itb.getAge();
453 		itb.setAge(oldAge + 1);
454 		assertTrue(modifiable.isModified());
455 		modifiable.acceptChanges();
456 		assertFalse(modifiable.isModified());
457 		itb.setAge(itb.getAge());
458 		assertFalse("Setting same value does not modify", modifiable.isModified());
459 		itb.setName("And now for something completely different");
460 		assertTrue(modifiable.isModified());
461 
462 		lockable.lock();
463 		assertTrue(lockable.locked());
464 		try {
465 			itb.setName("Else");
466 			fail("Should be locked");
467 		}
468 		catch (IllegalStateException ex) {
469 			// Ok
470 		}
471 		lockable.unlock();
472 		itb.setName("Tony");
473 	}
474 
475 	@Test
476 	public void testAspectMethodThrowsExceptionLegalOnSignature() {
477 		TestBean target = new TestBean();
478 		UnsupportedOperationException expectedException = new UnsupportedOperationException();
479 		List<Advisor> advisors = getFixture().getAdvisors(new SingletonMetadataAwareAspectInstanceFactory(new ExceptionAspect(expectedException),"someBean"));
480 		assertEquals("One advice method was found", 1, advisors.size());
481 		ITestBean itb = (ITestBean) createProxy(target,
482 				advisors,
483 				ITestBean.class);
484 		try {
485 			itb.getAge();
486 			fail();
487 		}
488 		catch (UnsupportedOperationException ex) {
489 			assertSame(expectedException, ex);
490 		}
491 	}
492 
493 	// TODO document this behaviour.
494 	// Is it different AspectJ behaviour, at least for checked exceptions?
495 	@Test
496 	public void testAspectMethodThrowsExceptionIllegalOnSignature() {
497 		TestBean target = new TestBean();
498 		RemoteException expectedException = new RemoteException();
499 		List<Advisor> advisors = getFixture().getAdvisors(new SingletonMetadataAwareAspectInstanceFactory(new ExceptionAspect(expectedException),"someBean"));
500 		assertEquals("One advice method was found", 1, advisors.size());
501 		ITestBean itb = (ITestBean) createProxy(target,
502 				advisors,
503 				ITestBean.class);
504 		try {
505 			itb.getAge();
506 			fail();
507 		}
508 		catch (UndeclaredThrowableException ex) {
509 			assertSame(expectedException, ex.getCause());
510 		}
511 	}
512 
513 	protected Object createProxy(Object target, List<Advisor> advisors, Class<?>... interfaces) {
514 		ProxyFactory pf = new ProxyFactory(target);
515 		if (interfaces.length > 1 || interfaces[0].isInterface()) {
516 			pf.setInterfaces(interfaces);
517 		}
518 		else {
519 			pf.setProxyTargetClass(true);
520 		}
521 
522 		// Required everywhere we use AspectJ proxies
523 		pf.addAdvice(ExposeInvocationInterceptor.INSTANCE);
524 
525 		for (Object a : advisors) {
526 			pf.addAdvisor((Advisor) a);
527 		}
528 
529 		pf.setExposeProxy(true);
530 		return pf.getProxy();
531 	}
532 
533 	@Test
534 	public void testTwoAdvicesOnOneAspect() {
535 		TestBean target = new TestBean();
536 
537 		TwoAdviceAspect twoAdviceAspect = new TwoAdviceAspect();
538 		List<Advisor> advisors = getFixture().getAdvisors(new SingletonMetadataAwareAspectInstanceFactory(twoAdviceAspect,"someBean"));
539 		assertEquals("Two advice methods found", 2, advisors.size());
540 		ITestBean itb = (ITestBean) createProxy(target,
541 				advisors,
542 				ITestBean.class);
543 		itb.setName("");
544 		assertEquals(0, itb.getAge());
545 		int newAge = 32;
546 		itb.setAge(newAge);
547 		assertEquals(1, itb.getAge());
548 	}
549 
550 	@Test
551 	public void testAfterAdviceTypes() throws Exception {
552 		Echo target = new Echo();
553 
554 		ExceptionHandling afterReturningAspect = new ExceptionHandling();
555 		List<Advisor> advisors = getFixture().getAdvisors(new SingletonMetadataAwareAspectInstanceFactory(afterReturningAspect,"someBean"));
556 		Echo echo = (Echo) createProxy(target,
557 				advisors,
558 				Echo.class);
559 		assertEquals(0, afterReturningAspect.successCount);
560 		assertEquals("", echo.echo(""));
561 		assertEquals(1, afterReturningAspect.successCount);
562 		assertEquals(0, afterReturningAspect.failureCount);
563 		try {
564 			echo.echo(new FileNotFoundException());
565 			fail();
566 		}
567 		catch (FileNotFoundException ex) {
568 			// Ok
569 		}
570 		catch (Exception ex) {
571 			fail();
572 		}
573 		assertEquals(1, afterReturningAspect.successCount);
574 		assertEquals(1, afterReturningAspect.failureCount);
575 		assertEquals(afterReturningAspect.failureCount + afterReturningAspect.successCount, afterReturningAspect.afterCount);
576 	}
577 
578 	@Test
579 	public void testFailureWithoutExplicitDeclarePrecedence() {
580 		TestBean target = new TestBean();
581 		MetadataAwareAspectInstanceFactory aspectInstanceFactory = new SingletonMetadataAwareAspectInstanceFactory(
582 			new NoDeclarePrecedenceShouldFail(), "someBean");
583 		ITestBean itb = (ITestBean) createProxy(target,
584 			getFixture().getAdvisors(aspectInstanceFactory), ITestBean.class);
585 		itb.getAge();
586 	}
587 
588 	@Test(expected=IllegalArgumentException.class)
589 	public void testDeclarePrecedenceNotSupported() {
590 		TestBean target = new TestBean();
591 		MetadataAwareAspectInstanceFactory aspectInstanceFactory = new SingletonMetadataAwareAspectInstanceFactory(
592 			new DeclarePrecedenceShouldSucceed(), "someBean");
593 		createProxy(target, getFixture().getAdvisors(aspectInstanceFactory),
594 			ITestBean.class);
595 	}
596 
597 	/** Not supported in 2.0!
598 	public void testExplicitDeclarePrecedencePreventsFailure() {
599 		TestBean target = new TestBean();
600 		ITestBean itb = (ITestBean) createProxy(target,
601 				getFixture().getAdvisors(new SingletonMetadataAwareAspectInstanceFactory(new DeclarePrecedenceShouldSucceed(), "someBean")),
602 				ITestBean.class);
603 		assertEquals(666, itb.getAge());
604 	}
605 	*/
606 
607 
608 	@Aspect("percflow(execution(* *(..)))")
609 	public static class PerCflowAspect {
610 	}
611 
612 
613 	@Aspect("percflowbelow(execution(* *(..)))")
614 	public static class PerCflowBelowAspect {
615 	}
616 
617 
618 	@Aspect("pertarget(execution(* *.getSpouse()))")
619 	@Order(10)
620 	public static class PerTargetAspectWithOrderAnnotation10 {
621 
622 		public int count;
623 
624 		@Around("execution(int *.getAge())")
625 		public int returnCountAsAge() {
626 			return count++;
627 		}
628 
629 		@Before("execution(void *.set*(int))")
630 		public void countSetter() {
631 			++count;
632 		}
633 	}
634 
635 
636 	@Aspect("pertarget(execution(* *.getSpouse()))")
637 	@Order(5)
638 	public static class PerTargetAspectWithOrderAnnotation5 {
639 
640 		public int count;
641 
642 		@Around("execution(int *.getAge())")
643 		public int returnCountAsAge() {
644 			return count++;
645 		}
646 
647 		@Before("execution(void *.set*(int))")
648 		public void countSetter() {
649 			++count;
650 		}
651 	}
652 
653 
654 	@Aspect("pertypewithin(org.springframework.tests.sample.beans.IOther+)")
655 	public static class PerTypeWithinAspect {
656 
657 		public int count;
658 
659 		@Around("execution(int *.getAge())")
660 		public int returnCountAsAge() {
661 			return count++;
662 		}
663 
664 		@Before("execution(void *.*(..))")
665 		public void countAnythingVoid() {
666 			++count;
667 		}
668 	}
669 
670 
671 	private class PerTypeWithinAspectInstanceFactory implements MetadataAwareAspectInstanceFactory {
672 
673 		private int count;
674 
675 		public int getInstantiationCount() {
676 			return this.count;
677 		}
678 
679 		@Override
680 		public Object getAspectInstance() {
681 			++this.count;
682 			return new PerTypeWithinAspect();
683 		}
684 
685 		@Override
686 		public ClassLoader getAspectClassLoader() {
687 			return PerTypeWithinAspect.class.getClassLoader();
688 		}
689 
690 		@Override
691 		public AspectMetadata getAspectMetadata() {
692 			return new AspectMetadata(PerTypeWithinAspect.class, "perTypeWithin");
693 		}
694 
695 		@Override
696 		public int getOrder() {
697 			return Ordered.LOWEST_PRECEDENCE;
698 		}
699 	}
700 
701 
702 	@Aspect
703 	public static class NamedPointcutAspectWithFQN {
704 
705 		private ITestBean fieldThatShouldBeIgnoredBySpringAtAspectJProcessing = new TestBean();
706 
707 		@Pointcut("execution(* getAge())")
708 		public void getAge() {
709 		}
710 
711 		@Around("org.springframework.aop.aspectj.annotation.AbstractAspectJAdvisorFactoryTests.NamedPointcutAspectWithFQN.getAge()")
712 		public int changeReturnValue(ProceedingJoinPoint pjp) {
713 			return -1;
714 		}
715 	}
716 
717 
718 	@Aspect
719 	public static class NamedPointcutAspectWithoutFQN {
720 		@Pointcut("execution(* getAge())")
721 		public void getAge() {
722 		}
723 
724 		@Around("getAge()")
725 		public int changeReturnValue(ProceedingJoinPoint pjp) {
726 			return -1;
727 		}
728 	}
729 
730 
731 	@Aspect
732 	public static class NamedPointcutAspectFromLibrary {
733 
734 		@Around("org.springframework.aop.aspectj.annotation.AbstractAspectJAdvisorFactoryTests.Library.propertyAccess()")
735 		public int changeReturnType(ProceedingJoinPoint pjp) {
736 			return -1;
737 		}
738 
739 		@Around(value="org.springframework.aop.aspectj.annotation.AbstractAspectJAdvisorFactoryTests.Library.integerArgOperation(x)", argNames="x")
740 		public void doubleArg(ProceedingJoinPoint pjp, int x) throws Throwable {
741 			pjp.proceed(new Object[] {x*2});
742 		}
743 	}
744 
745 
746 	@Aspect
747 	public static class Library {
748 
749 		@Pointcut("execution(!void get*())")
750 		public void propertyAccess() {}
751 
752 		@Pointcut("execution(* *(..)) && args(i)")
753 		public void integerArgOperation(int i) {}
754 
755 	}
756 
757 
758 	@Aspect
759 	public static class NamedPointcutAspectFromLibraryWithBinding {
760 
761 		@Around(value="org.springframework.aop.aspectj.annotation.AbstractAspectJAdvisorFactoryTests.Library.integerArgOperation(x)", argNames="x")
762 		public void doubleArg(ProceedingJoinPoint pjp, int x) throws Throwable {
763 			pjp.proceed(new Object[] {x*2});
764 		}
765 	}
766 
767 
768 	@Aspect
769 	public static class BindingAspectWithSingleArg {
770 
771 		@Pointcut(value="args(a)", argNames="a")
772 		public void setAge(int a) {}
773 
774 		@Around(value="setAge(age)",argNames="age")
775 		// @ArgNames({"age"})	// AMC needs more work here? ignoring pjp arg... ok??
776 								// argNames should be suported in Around as it is in Pointcut
777 		public void changeReturnType(ProceedingJoinPoint pjp, int age) throws Throwable {
778 			pjp.proceed(new Object[] {age*2});
779 		}
780 	}
781 
782 
783 	@Aspect
784 	public static class ManyValuedArgs {
785 		public String mungeArgs(String a, int b, int c, String d, StringBuffer e) {
786 			return a + b + c + d + e;
787 		}
788 
789 		@Around(value="execution(String mungeArgs(..)) && args(a, b, c, d, e)",
790 				argNames="b,c,d,e,a")
791 		public String reverseAdvice(ProceedingJoinPoint pjp, int b, int c, String d, StringBuffer e, String a) throws Throwable {
792 			assertEquals(a + b+ c+ d+ e, pjp.proceed());
793 			return a + b + c + d + e;
794 		}
795 	}
796 
797 
798 	@Aspect
799 	public static class ExceptionAspect {
800 		private final Exception ex;
801 
802 		public ExceptionAspect(Exception ex) {
803 			this.ex = ex;
804 		}
805 
806 		@Before("execution(* getAge())")
807 		public void throwException() throws Exception {
808 			throw ex;
809 		}
810 	}
811 
812 
813 	public static class Echo {
814 
815 		public Object echo(Object o) throws Exception {
816 			if (o instanceof Exception) {
817 				throw (Exception) o;
818 			}
819 			return o;
820 		}
821 	}
822 
823 
824 	@Aspect
825 	public static class ExceptionHandling {
826 		public int successCount;
827 		public int failureCount;
828 		public int afterCount;
829 
830 		@AfterReturning("execution(* echo(*))")
831 		public void succeeded() {
832 			++successCount;
833 		}
834 
835 		@AfterThrowing("execution(* echo(*))")
836 		public void failed() {
837 			++failureCount;
838 		}
839 
840 		@After("execution(* echo(*))")
841 		public void invoked() {
842 			++afterCount;
843 		}
844 	}
845 
846 
847 	@Aspect
848 	public static class NoDeclarePrecedenceShouldFail {
849 
850 		@Pointcut("execution(int *.getAge())")
851 		public void getAge() {
852 		}
853 
854 		@Before("getAge()")
855 		public void blowUpButDoesntMatterBecauseAroundAdviceWontLetThisBeInvoked() {
856 			throw new IllegalStateException();
857 		}
858 
859 		@Around("getAge()")
860 		public int preventExecution(ProceedingJoinPoint pjp) {
861 			return 666;
862 		}
863 	}
864 
865 
866 	@Aspect
867 	@DeclarePrecedence("test..*")
868 	public static class DeclarePrecedenceShouldSucceed {
869 
870 		@Pointcut("execution(int *.getAge())")
871 		public void getAge() {
872 		}
873 
874 		@Before("getAge()")
875 		public void blowUpButDoesntMatterBecauseAroundAdviceWontLetThisBeInvoked() {
876 			throw new IllegalStateException();
877 		}
878 
879 		@Around("getAge()")
880 		public int preventExecution(ProceedingJoinPoint pjp) {
881 			return 666;
882 		}
883 	}
884 
885 }
886 
887 
888 /**
889  * Add a DeclareParents field in concrete subclasses, to identify
890  * the type pattern to apply the introduction to.
891  *
892  * @author Rod Johnson
893  * @since 2.0
894  */
895 @Aspect
896 abstract class AbstractMakeModifiable {
897 
898 	public interface MutableModifable extends Modifiable {
899 		void markDirty();
900 	}
901 
902 	public static class ModifiableImpl implements MutableModifable {
903 		private boolean modified;
904 
905 		@Override
906 		public void acceptChanges() {
907 			modified = false;
908 		}
909 
910 		@Override
911 		public boolean isModified() {
912 			return modified;
913 		}
914 
915 		@Override
916 		public void markDirty() {
917 			this.modified = true;
918 		}
919 	}
920 
921 	@Before(value="execution(void set*(*)) && this(modifiable) && args(newValue)",
922 			argNames="modifiable,newValue")
923 	public void recordModificationIfSetterArgumentDiffersFromOldValue(JoinPoint jp,
924 		MutableModifable mixin, Object newValue) {
925 
926 		/*
927 		 * We use the mixin to check and, if necessary, change,
928 		 * modification status. We need the JoinPoint to get the
929 		 * setter method. We use newValue for comparison.
930 		 * We try to invoke the getter if possible.
931 		 */
932 
933 		if (mixin.isModified()) {
934 			// Already changed, don't need to change again
935 			//System.out.println("changed");
936 			return;
937 		}
938 
939 		// Find the current raw value, by invoking the corresponding setter
940 		Method correspondingGetter = getGetterFromSetter(((MethodSignature) jp.getSignature()).getMethod());
941 		boolean modified = true;
942 		if (correspondingGetter != null) {
943 			try {
944 				Object oldValue = correspondingGetter.invoke(jp.getTarget());
945 				//System.out.println("Old value=" + oldValue + "; new=" + newValue);
946 				modified = !ObjectUtils.nullSafeEquals(oldValue, newValue);
947 			}
948 			catch (Exception ex) {
949 				ex.printStackTrace();
950 				// Don't sweat on exceptions; assume value was modified
951 			}
952 		}
953 		else {
954 			//System.out.println("cannot get getter for " + jp);
955 		}
956 		if (modified) {
957 			mixin.markDirty();
958 		}
959 	}
960 
961 	private Method getGetterFromSetter(Method setter) {
962 		String getterName = setter.getName().replaceFirst("set", "get");
963 		try {
964 			return setter.getDeclaringClass().getMethod(getterName, (Class[]) null);
965 		}
966 		catch (NoSuchMethodException ex) {
967 			// must be write only
968 			return null;
969 		}
970 	}
971 
972 }
973 
974 
975 /**
976  * Adds a declare parents pointcut.
977  * @author Rod Johnson
978  * @since 2.0
979  */
980 @Aspect
981 class MakeITestBeanModifiable extends AbstractMakeModifiable {
982 
983 	@DeclareParents(value = "org.springframework.tests.sample.beans.ITestBean+",
984 			defaultImpl=ModifiableImpl.class)
985 	public static MutableModifable mixin;
986 
987 }
988 
989 /**
990  * Adds a declare parents pointcut - spr5307
991  * @author Andy Clement
992  * @since 3.0
993  */
994 @Aspect
995 class MakeAnnotatedTypeModifiable extends AbstractMakeModifiable {
996 
997 	@DeclareParents(value = "(@org.springframework.aop.aspectj.annotation.Measured *)",
998 //	@DeclareParents(value = "(@Measured *)", // this would be a nice alternative...
999 			defaultImpl=DefaultLockable.class)
1000 	public static Lockable mixin;
1001 
1002 }
1003 
1004 
1005 /**
1006  * Demonstrates introductions, AspectJ annotation style.
1007  */
1008 @Aspect
1009 class MakeLockable {
1010 
1011 	@DeclareParents(value = "org.springframework..*",
1012 			defaultImpl=DefaultLockable.class)
1013 	public static Lockable mixin;
1014 
1015 	@Before(value="execution(void set*(*)) && this(mixin)", argNames="mixin")
1016 	public void checkNotLocked(
1017 		Lockable mixin)  // Bind to arg
1018 	{
1019 		// Can also obtain the mixin (this) this way
1020 		//Lockable mixin = (Lockable) jp.getThis();
1021 		if (mixin.locked()) {
1022 			throw new IllegalStateException();
1023 		}
1024 	}
1025 
1026 }
1027 
1028 
1029 class CannotBeUnlocked implements Lockable, Comparable<Object> {
1030 
1031 	@Override
1032 	public void lock() {
1033 	}
1034 
1035 	@Override
1036 	public void unlock() {
1037 		throw new UnsupportedOperationException();
1038 	}
1039 
1040 	@Override
1041 	public boolean locked() {
1042 		return true;
1043 	}
1044 
1045 	@Override
1046 	public int compareTo(Object arg0) {
1047 		throw new UnsupportedOperationException();
1048 	}
1049 
1050 }
1051 
1052 
1053 /**
1054  * Used as a mixin.
1055  *
1056  * @author Rod Johnson
1057  */
1058 interface Modifiable {
1059 
1060 	boolean isModified();
1061 
1062 	void acceptChanges();
1063 
1064 }
1065 
1066 /**
1067  * Used as a target.
1068  * @author Andy Clement
1069  */
1070 interface AnnotatedTarget {
1071 }
1072 
1073 @Measured
1074 class AnnotatedTargetImpl implements AnnotatedTarget {
1075 
1076 }
1077 
1078 @Retention(RetentionPolicy.RUNTIME)
1079 @interface Measured {}
1080 
1081 class NotLockable {
1082 
1083 	private int intValue;
1084 
1085 	public int getIntValue() {
1086 		return intValue;
1087 	}
1088 
1089 	public void setIntValue(int intValue) {
1090 		this.intValue = intValue;
1091 	}
1092 
1093 }
1094 
1095 
1096 @Aspect("perthis(execution(* *.getSpouse()))")
1097 class PerThisAspect {
1098 
1099 	public int count;
1100 
1101 	/**
1102 	 * Just to check that this doesn't cause problems with introduction processing
1103 	 */
1104 	private ITestBean fieldThatShouldBeIgnoredBySpringAtAspectJProcessing = new TestBean();
1105 
1106 	@Around("execution(int *.getAge())")
1107 	public int returnCountAsAge() {
1108 		return count++;
1109 	}
1110 
1111 	@Before("execution(void *.set*(int))")
1112 	public void countSetter() {
1113 		++count;
1114 	}
1115 
1116 }