Package org.springframework.aop.aspectj.annotation

Source Code of org.springframework.aop.aspectj.annotation.AbstractAspectJAdvisorFactoryTests

/*
* Copyright 2002-2014 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*      http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.aop.aspectj.annotation;

import java.io.FileNotFoundException;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.reflect.Method;
import java.lang.reflect.UndeclaredThrowableException;
import java.rmi.RemoteException;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.DeclareParents;
import org.aspectj.lang.annotation.DeclarePrecedence;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.junit.Ignore;
import org.junit.Test;
import test.aop.DefaultLockable;
import test.aop.Lockable;
import test.aop.PerTargetAspect;
import test.aop.TwoAdviceAspect;

import org.springframework.aop.Advisor;
import org.springframework.aop.aspectj.annotation.ReflectiveAspectJAdvisorFactory.SyntheticInstantiationAdvisor;
import org.springframework.aop.framework.Advised;
import org.springframework.aop.framework.AopConfigException;
import org.springframework.aop.framework.ProxyFactory;
import org.springframework.aop.interceptor.ExposeInvocationInterceptor;
import org.springframework.aop.support.AopUtils;
import org.springframework.core.OrderComparator;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.tests.sample.beans.ITestBean;
import org.springframework.tests.sample.beans.TestBean;
import org.springframework.util.ObjectUtils;

import static org.hamcrest.Matchers.*;
import static org.junit.Assert.*;

/**
* Abstract tests for AspectJAdvisorFactory.
* See subclasses for tests of concrete factories.
*
* @author Rod Johnson
* @author Chris Beams
* @author Phillip Webb
*/
public abstract class AbstractAspectJAdvisorFactoryTests {

  /**
   * To be overridden by concrete test subclasses.
   * @return the fixture
   */
  protected abstract AspectJAdvisorFactory getFixture();


  @Test
  public void testRejectsPerCflowAspect() {
    try {
      getFixture().getAdvisors(new SingletonMetadataAwareAspectInstanceFactory(new PerCflowAspect(),"someBean"));
      fail("Cannot accept cflow");
    }
    catch (AopConfigException ex) {
      assertTrue(ex.getMessage().indexOf("PERCFLOW") != -1);
    }
  }

  @Test
  public void testRejectsPerCflowBelowAspect() {
    try {
      getFixture().getAdvisors(new SingletonMetadataAwareAspectInstanceFactory(new PerCflowBelowAspect(),"someBean"));
      fail("Cannot accept cflowbelow");
    }
    catch (AopConfigException ex) {
      assertTrue(ex.getMessage().indexOf("PERCFLOWBELOW") != -1);
    }
  }

  @Test
  public void testPerTargetAspect() throws SecurityException, NoSuchMethodException {
    TestBean target = new TestBean();
    int realAge = 65;
    target.setAge(realAge);
    TestBean itb = (TestBean) createProxy(target,
        getFixture().getAdvisors(new SingletonMetadataAwareAspectInstanceFactory(new PerTargetAspect(), "someBean")),
        TestBean.class);
    assertEquals("Around advice must NOT apply", realAge, itb.getAge());

    Advised advised = (Advised) itb;
    SyntheticInstantiationAdvisor sia = (SyntheticInstantiationAdvisor) advised.getAdvisors()[1];
    assertTrue(sia.getPointcut().getMethodMatcher().matches(TestBean.class.getMethod("getSpouse"), null));
    InstantiationModelAwarePointcutAdvisorImpl imapa = (InstantiationModelAwarePointcutAdvisorImpl) advised.getAdvisors()[3];
    LazySingletonAspectInstanceFactoryDecorator maaif =
        (LazySingletonAspectInstanceFactoryDecorator) imapa.getAspectInstanceFactory();
    assertFalse(maaif.isMaterialized());

    // Check that the perclause pointcut is valid
    assertTrue(maaif.getAspectMetadata().getPerClausePointcut().getMethodMatcher().matches(TestBean.class.getMethod("getSpouse"), null));
    assertNotSame(imapa.getDeclaredPointcut(), imapa.getPointcut());

    // Hit the method in the per clause to instantiate the aspect
    itb.getSpouse();

    assertTrue(maaif.isMaterialized());

    assertEquals("Around advice must apply", 0, itb.getAge());
    assertEquals("Around advice must apply", 1, itb.getAge());
  }

  @Test
  public void testMultiplePerTargetAspects() throws SecurityException, NoSuchMethodException {
    TestBean target = new TestBean();
    int realAge = 65;
    target.setAge(realAge);

    List<Advisor> advisors = new LinkedList<Advisor>();
    PerTargetAspect aspect1 = new PerTargetAspect();
    aspect1.count = 100;
    aspect1.setOrder(10);
    advisors.addAll(
        getFixture().getAdvisors(new SingletonMetadataAwareAspectInstanceFactory(aspect1, "someBean1")));
    PerTargetAspect aspect2 = new PerTargetAspect();
    aspect2.setOrder(5);
    advisors.addAll(
        getFixture().getAdvisors(new SingletonMetadataAwareAspectInstanceFactory(aspect2, "someBean2")));
    Collections.sort(advisors, new OrderComparator());

    TestBean itb = (TestBean) createProxy(target, advisors, TestBean.class);
    assertEquals("Around advice must NOT apply", realAge, itb.getAge());

    // Hit the method in the per clause to instantiate the aspect
    itb.getSpouse();

    assertEquals("Around advice must apply", 0, itb.getAge());
    assertEquals("Around advice must apply", 1, itb.getAge());
  }

  @Test
  public void testMultiplePerTargetAspectsWithOrderAnnotation() throws SecurityException, NoSuchMethodException {
    TestBean target = new TestBean();
    int realAge = 65;
    target.setAge(realAge);

    List<Advisor> advisors = new LinkedList<Advisor>();
    PerTargetAspectWithOrderAnnotation10 aspect1 = new PerTargetAspectWithOrderAnnotation10();
    aspect1.count = 100;
    advisors.addAll(
        getFixture().getAdvisors(new SingletonMetadataAwareAspectInstanceFactory(aspect1, "someBean1")));
    PerTargetAspectWithOrderAnnotation5 aspect2 = new PerTargetAspectWithOrderAnnotation5();
    advisors.addAll(
        getFixture().getAdvisors(new SingletonMetadataAwareAspectInstanceFactory(aspect2, "someBean2")));
    Collections.sort(advisors, new OrderComparator());

    TestBean itb = (TestBean) createProxy(target, advisors, TestBean.class);
    assertEquals("Around advice must NOT apply", realAge, itb.getAge());

    // Hit the method in the per clause to instantiate the aspect
    itb.getSpouse();

    assertEquals("Around advice must apply", 0, itb.getAge());
    assertEquals("Around advice must apply", 1, itb.getAge());
  }

  @Test
  public void testPerThisAspect() throws SecurityException, NoSuchMethodException {
    TestBean target = new TestBean();
    int realAge = 65;
    target.setAge(realAge);
    TestBean itb = (TestBean) createProxy(target,
        getFixture().getAdvisors(new SingletonMetadataAwareAspectInstanceFactory(new PerThisAspect(), "someBean")),
        TestBean.class);
    assertEquals("Around advice must NOT apply", realAge, itb.getAge());

    Advised advised = (Advised) itb;
    // Will be ExposeInvocationInterceptor, synthetic instantiation advisor, 2 method advisors
    assertEquals(4, advised.getAdvisors().length);
    SyntheticInstantiationAdvisor sia = (SyntheticInstantiationAdvisor) advised.getAdvisors()[1];
    assertTrue(sia.getPointcut().getMethodMatcher().matches(TestBean.class.getMethod("getSpouse"), null));
    InstantiationModelAwarePointcutAdvisorImpl imapa = (InstantiationModelAwarePointcutAdvisorImpl) advised.getAdvisors()[2];
    LazySingletonAspectInstanceFactoryDecorator maaif =
        (LazySingletonAspectInstanceFactoryDecorator) imapa.getAspectInstanceFactory();
    assertFalse(maaif.isMaterialized());

    // Check that the perclause pointcut is valid
    assertTrue(maaif.getAspectMetadata().getPerClausePointcut().getMethodMatcher().matches(TestBean.class.getMethod("getSpouse"), null));
    assertNotSame(imapa.getDeclaredPointcut(), imapa.getPointcut());

    // Hit the method in the per clause to instantiate the aspect
    itb.getSpouse();

    assertTrue(maaif.isMaterialized());

    assertTrue(imapa.getDeclaredPointcut().getMethodMatcher().matches(TestBean.class.getMethod("getAge"), null));

    assertEquals("Around advice must apply", 0, itb.getAge());
    assertEquals("Around advice must apply", 1, itb.getAge());
  }

  @Test
  public void testPerTypeWithinAspect() throws SecurityException, NoSuchMethodException {
    TestBean target = new TestBean();
    int realAge = 65;
    target.setAge(realAge);
    PerTypeWithinAspectInstanceFactory aif = new PerTypeWithinAspectInstanceFactory();
    TestBean itb = (TestBean) createProxy(target,
        getFixture().getAdvisors(aif),
        TestBean.class);
    assertEquals("No method calls", 0, aif.getInstantiationCount());
    assertEquals("Around advice must now apply", 0, itb.getAge());

    Advised advised = (Advised) itb;
    // Will be ExposeInvocationInterceptor, synthetic instantiation advisor, 2 method advisors
    assertEquals(4, advised.getAdvisors().length);
    SyntheticInstantiationAdvisor sia = (SyntheticInstantiationAdvisor) advised.getAdvisors()[1];
    assertTrue(sia.getPointcut().getMethodMatcher().matches(TestBean.class.getMethod("getSpouse"), null));
    InstantiationModelAwarePointcutAdvisorImpl imapa = (InstantiationModelAwarePointcutAdvisorImpl) advised.getAdvisors()[2];
    LazySingletonAspectInstanceFactoryDecorator maaif =
        (LazySingletonAspectInstanceFactoryDecorator) imapa.getAspectInstanceFactory();
    assertTrue(maaif.isMaterialized());

    // Check that the perclause pointcut is valid
    assertTrue(maaif.getAspectMetadata().getPerClausePointcut().getMethodMatcher().matches(TestBean.class.getMethod("getSpouse"), null));
    assertNotSame(imapa.getDeclaredPointcut(), imapa.getPointcut());

    // Hit the method in the per clause to instantiate the aspect
    itb.getSpouse();

    assertTrue(maaif.isMaterialized());

    assertTrue(imapa.getDeclaredPointcut().getMethodMatcher().matches(TestBean.class.getMethod("getAge"), null));

    assertEquals("Around advice must still apply", 1, itb.getAge());
    assertEquals("Around advice must still apply", 2, itb.getAge());

    TestBean itb2 = (TestBean) createProxy(target,
        getFixture().getAdvisors(aif),
        TestBean.class);
    assertEquals(1, aif.getInstantiationCount());
    assertEquals("Around advice be independent for second instance", 0, itb2.getAge());
    assertEquals(2, aif.getInstantiationCount());
  }

  @Test
  public void testNamedPointcutAspectWithFQN() {
    testNamedPointcuts(new NamedPointcutAspectWithFQN());
  }

  @Test
  public void testNamedPointcutAspectWithoutFQN() {
    testNamedPointcuts(new NamedPointcutAspectWithoutFQN());
  }

  @Test
  public void testNamedPointcutFromAspectLibrary() {
    testNamedPointcuts(new NamedPointcutAspectFromLibrary());
  }

  @Test
  public void testNamedPointcutFromAspectLibraryWithBinding() {
    TestBean target = new TestBean();
    ITestBean itb = (ITestBean) createProxy(target,
        getFixture().getAdvisors(new SingletonMetadataAwareAspectInstanceFactory(new NamedPointcutAspectFromLibraryWithBinding(),"someBean")),
        ITestBean.class);
    itb.setAge(10);
    assertEquals("Around advice must apply", 20, itb.getAge());
    assertEquals(20,target.getAge());
  }

  private void testNamedPointcuts(Object aspectInstance) {
    TestBean target = new TestBean();
    int realAge = 65;
    target.setAge(realAge);
    ITestBean itb = (ITestBean) createProxy(target,
        getFixture().getAdvisors(new SingletonMetadataAwareAspectInstanceFactory(aspectInstance,"someBean")),
        ITestBean.class);
    assertEquals("Around advice must apply", -1, itb.getAge());
    assertEquals(realAge, target.getAge());
  }

  @Test
  public void testBindingWithSingleArg() {
    TestBean target = new TestBean();
    ITestBean itb = (ITestBean) createProxy(target,
        getFixture().getAdvisors(new SingletonMetadataAwareAspectInstanceFactory(new BindingAspectWithSingleArg(),"someBean")),
        ITestBean.class);
    itb.setAge(10);
    assertEquals("Around advice must apply", 20, itb.getAge());
    assertEquals(20,target.getAge());
  }

  @Test
  public void testBindingWithMultipleArgsDifferentlyOrdered() {
    ManyValuedArgs target = new ManyValuedArgs();
    ManyValuedArgs mva = (ManyValuedArgs) createProxy(target,
        getFixture().getAdvisors(new SingletonMetadataAwareAspectInstanceFactory(new ManyValuedArgs(),"someBean")),
        ManyValuedArgs.class);

    String a = "a";
    int b = 12;
    int c = 25;
    String d = "d";
    StringBuffer e = new StringBuffer("stringbuf");
    String expectedResult = a + b+ c + d + e;
    assertEquals(expectedResult, mva.mungeArgs(a, b, c, d, e));
  }

  /**
   * In this case the introduction will be made.
   */
  @Test
  public void testIntroductionOnTargetNotImplementingInterface() {
    NotLockable notLockableTarget = new NotLockable();
    assertFalse(notLockableTarget instanceof Lockable);
    NotLockable notLockable1 = (NotLockable) createProxy(notLockableTarget,
        getFixture().getAdvisors(
            new SingletonMetadataAwareAspectInstanceFactory(new MakeLockable(),"someBean")),
        NotLockable.class);
    assertTrue(notLockable1 instanceof Lockable);
    Lockable lockable = (Lockable) notLockable1;
    assertFalse(lockable.locked());
    lockable.lock();
    assertTrue(lockable.locked());

    NotLockable notLockable2Target = new NotLockable();
    NotLockable notLockable2 = (NotLockable) createProxy(notLockable2Target,
        getFixture().getAdvisors(
            new SingletonMetadataAwareAspectInstanceFactory(new MakeLockable(),"someBean")),
        NotLockable.class);
    assertTrue(notLockable2 instanceof Lockable);
    Lockable lockable2 = (Lockable) notLockable2;
    assertFalse(lockable2.locked());
    notLockable2.setIntValue(1);
    lockable2.lock();
    try {
      notLockable2.setIntValue(32);
      fail();
    }
    catch (IllegalStateException ex) {
    }
    assertTrue(lockable2.locked());
  }

  @Test
  public void testIntroductionAdvisorExcludedFromTargetImplementingInterface() {
    assertTrue(AopUtils.findAdvisorsThatCanApply(
            getFixture().getAdvisors(
                  new SingletonMetadataAwareAspectInstanceFactory(
                      new MakeLockable(),"someBean")),
            CannotBeUnlocked.class).isEmpty());
    assertEquals(2, AopUtils.findAdvisorsThatCanApply(getFixture().getAdvisors(new SingletonMetadataAwareAspectInstanceFactory(new MakeLockable(),"someBean")), NotLockable.class).size());
  }

  @Test
  public void testIntroductionOnTargetImplementingInterface() {
    CannotBeUnlocked target = new CannotBeUnlocked();
    Lockable proxy = (Lockable) createProxy(target,
        // Ensure that we exclude
        AopUtils.findAdvisorsThatCanApply(
            getFixture().getAdvisors(
                new SingletonMetadataAwareAspectInstanceFactory(new MakeLockable(), "someBean")),
            CannotBeUnlocked.class
        ),
        CannotBeUnlocked.class);
    assertThat(proxy, instanceOf(Lockable.class));
    Lockable lockable = proxy;
    assertTrue("Already locked", lockable.locked());
    lockable.lock();
    assertTrue("Real target ignores locking", lockable.locked());
    try {
      lockable.unlock();
      fail();
    }
    catch (UnsupportedOperationException ex) {
      // Ok
    }
  }

  @Test
  public void testIntroductionOnTargetExcludedByTypePattern() {
    LinkedList<Object> target = new LinkedList<Object>();
    List<?> proxy = (List<?>) createProxy(target,
        AopUtils.findAdvisorsThatCanApply(
            getFixture().getAdvisors(new SingletonMetadataAwareAspectInstanceFactory(new MakeLockable(), "someBean")),
            List.class
        ),
        CannotBeUnlocked.class);
    assertFalse("Type pattern must have excluded mixin", proxy instanceof Lockable);
  }

  /* prereq AspectJ 1.6.7
  @Test
  public void testIntroductionBasedOnAnnotationMatch_Spr5307() {
    AnnotatedTarget target = new AnnotatedTargetImpl();

    List<Advisor> advisors = getFixture().getAdvisors(
        new SingletonMetadataAwareAspectInstanceFactory(new MakeAnnotatedTypeModifiable(),"someBean"));
    Object proxy = createProxy(target,
        advisors,
        AnnotatedTarget.class);
    System.out.println(advisors.get(1));
    assertTrue(proxy instanceof Lockable);
    Lockable lockable = (Lockable)proxy;
    lockable.locked();
  }
  */

  // TODO: Why does this test fail? It hasn't been run before, so it maybe never actually passed...

  @Test
  @Ignore
  public void testIntroductionWithArgumentBinding() {
    TestBean target = new TestBean();

    List<Advisor> advisors = getFixture().getAdvisors(
        new SingletonMetadataAwareAspectInstanceFactory(new MakeITestBeanModifiable(),"someBean"));
    advisors.addAll(getFixture().getAdvisors(
        new SingletonMetadataAwareAspectInstanceFactory(new MakeLockable(),"someBean")));

    Modifiable modifiable = (Modifiable) createProxy(target,
        advisors,
        ITestBean.class);
    assertThat(modifiable, instanceOf(Modifiable.class));
    Lockable lockable = (Lockable) modifiable;
    assertFalse(lockable.locked());

    ITestBean itb = (ITestBean) modifiable;
    assertFalse(modifiable.isModified());
    int oldAge = itb.getAge();
    itb.setAge(oldAge + 1);
    assertTrue(modifiable.isModified());
    modifiable.acceptChanges();
    assertFalse(modifiable.isModified());
    itb.setAge(itb.getAge());
    assertFalse("Setting same value does not modify", modifiable.isModified());
    itb.setName("And now for something completely different");
    assertTrue(modifiable.isModified());

    lockable.lock();
    assertTrue(lockable.locked());
    try {
      itb.setName("Else");
      fail("Should be locked");
    }
    catch (IllegalStateException ex) {
      // Ok
    }
    lockable.unlock();
    itb.setName("Tony");
  }

  @Test
  public void testAspectMethodThrowsExceptionLegalOnSignature() {
    TestBean target = new TestBean();
    UnsupportedOperationException expectedException = new UnsupportedOperationException();
    List<Advisor> advisors = getFixture().getAdvisors(new SingletonMetadataAwareAspectInstanceFactory(new ExceptionAspect(expectedException),"someBean"));
    assertEquals("One advice method was found", 1, advisors.size());
    ITestBean itb = (ITestBean) createProxy(target,
        advisors,
        ITestBean.class);
    try {
      itb.getAge();
      fail();
    }
    catch (UnsupportedOperationException ex) {
      assertSame(expectedException, ex);
    }
  }

  // TODO document this behaviour.
  // Is it different AspectJ behaviour, at least for checked exceptions?
  @Test
  public void testAspectMethodThrowsExceptionIllegalOnSignature() {
    TestBean target = new TestBean();
    RemoteException expectedException = new RemoteException();
    List<Advisor> advisors = getFixture().getAdvisors(new SingletonMetadataAwareAspectInstanceFactory(new ExceptionAspect(expectedException),"someBean"));
    assertEquals("One advice method was found", 1, advisors.size());
    ITestBean itb = (ITestBean) createProxy(target,
        advisors,
        ITestBean.class);
    try {
      itb.getAge();
      fail();
    }
    catch (UndeclaredThrowableException ex) {
      assertSame(expectedException, ex.getCause());
    }
  }

  protected Object createProxy(Object target, List<Advisor> advisors, Class<?>... interfaces) {
    ProxyFactory pf = new ProxyFactory(target);
    if (interfaces.length > 1 || interfaces[0].isInterface()) {
      pf.setInterfaces(interfaces);
    }
    else {
      pf.setProxyTargetClass(true);
    }

    // Required everywhere we use AspectJ proxies
    pf.addAdvice(ExposeInvocationInterceptor.INSTANCE);

    for (Object a : advisors) {
      pf.addAdvisor((Advisor) a);
    }

    pf.setExposeProxy(true);
    return pf.getProxy();
  }

  @Test
  public void testTwoAdvicesOnOneAspect() {
    TestBean target = new TestBean();

    TwoAdviceAspect twoAdviceAspect = new TwoAdviceAspect();
    List<Advisor> advisors = getFixture().getAdvisors(new SingletonMetadataAwareAspectInstanceFactory(twoAdviceAspect,"someBean"));
    assertEquals("Two advice methods found", 2, advisors.size());
    ITestBean itb = (ITestBean) createProxy(target,
        advisors,
        ITestBean.class);
    itb.setName("");
    assertEquals(0, itb.getAge());
    int newAge = 32;
    itb.setAge(newAge);
    assertEquals(1, itb.getAge());
  }

  @Test
  public void testAfterAdviceTypes() throws Exception {
    Echo target = new Echo();

    ExceptionHandling afterReturningAspect = new ExceptionHandling();
    List<Advisor> advisors = getFixture().getAdvisors(new SingletonMetadataAwareAspectInstanceFactory(afterReturningAspect,"someBean"));
    Echo echo = (Echo) createProxy(target,
        advisors,
        Echo.class);
    assertEquals(0, afterReturningAspect.successCount);
    assertEquals("", echo.echo(""));
    assertEquals(1, afterReturningAspect.successCount);
    assertEquals(0, afterReturningAspect.failureCount);
    try {
      echo.echo(new FileNotFoundException());
      fail();
    }
    catch (FileNotFoundException ex) {
      // Ok
    }
    catch (Exception ex) {
      fail();
    }
    assertEquals(1, afterReturningAspect.successCount);
    assertEquals(1, afterReturningAspect.failureCount);
    assertEquals(afterReturningAspect.failureCount + afterReturningAspect.successCount, afterReturningAspect.afterCount);
  }

  @Test
  public void testFailureWithoutExplicitDeclarePrecedence() {
    TestBean target = new TestBean();
    MetadataAwareAspectInstanceFactory aspectInstanceFactory = new SingletonMetadataAwareAspectInstanceFactory(
      new NoDeclarePrecedenceShouldFail(), "someBean");
    ITestBean itb = (ITestBean) createProxy(target,
      getFixture().getAdvisors(aspectInstanceFactory), ITestBean.class);
    itb.getAge();
  }

  @Test(expected=IllegalArgumentException.class)
  public void testDeclarePrecedenceNotSupported() {
    TestBean target = new TestBean();
    MetadataAwareAspectInstanceFactory aspectInstanceFactory = new SingletonMetadataAwareAspectInstanceFactory(
      new DeclarePrecedenceShouldSucceed(), "someBean");
    createProxy(target, getFixture().getAdvisors(aspectInstanceFactory),
      ITestBean.class);
  }

  /** Not supported in 2.0!
  public void testExplicitDeclarePrecedencePreventsFailure() {
    TestBean target = new TestBean();
    ITestBean itb = (ITestBean) createProxy(target,
        getFixture().getAdvisors(new SingletonMetadataAwareAspectInstanceFactory(new DeclarePrecedenceShouldSucceed(), "someBean")),
        ITestBean.class);
    assertEquals(666, itb.getAge());
  }
  */


  @Aspect("percflow(execution(* *(..)))")
  public static class PerCflowAspect {
  }


  @Aspect("percflowbelow(execution(* *(..)))")
  public static class PerCflowBelowAspect {
  }


  @Aspect("pertarget(execution(* *.getSpouse()))")
  @Order(10)
  public static class PerTargetAspectWithOrderAnnotation10 {

    public int count;

    @Around("execution(int *.getAge())")
    public int returnCountAsAge() {
      return count++;
    }

    @Before("execution(void *.set*(int))")
    public void countSetter() {
      ++count;
    }
  }


  @Aspect("pertarget(execution(* *.getSpouse()))")
  @Order(5)
  public static class PerTargetAspectWithOrderAnnotation5 {

    public int count;

    @Around("execution(int *.getAge())")
    public int returnCountAsAge() {
      return count++;
    }

    @Before("execution(void *.set*(int))")
    public void countSetter() {
      ++count;
    }
  }


  @Aspect("pertypewithin(org.springframework.tests.sample.beans.IOther+)")
  public static class PerTypeWithinAspect {

    public int count;

    @Around("execution(int *.getAge())")
    public int returnCountAsAge() {
      return count++;
    }

    @Before("execution(void *.*(..))")
    public void countAnythingVoid() {
      ++count;
    }
  }


  private class PerTypeWithinAspectInstanceFactory implements MetadataAwareAspectInstanceFactory {

    private int count;

    public int getInstantiationCount() {
      return this.count;
    }

    @Override
    public Object getAspectInstance() {
      ++this.count;
      return new PerTypeWithinAspect();
    }

    @Override
    public ClassLoader getAspectClassLoader() {
      return PerTypeWithinAspect.class.getClassLoader();
    }

    @Override
    public AspectMetadata getAspectMetadata() {
      return new AspectMetadata(PerTypeWithinAspect.class, "perTypeWithin");
    }

    @Override
    public int getOrder() {
      return Ordered.LOWEST_PRECEDENCE;
    }
  }


  @Aspect
  public static class NamedPointcutAspectWithFQN {

    private ITestBean fieldThatShouldBeIgnoredBySpringAtAspectJProcessing = new TestBean();

    @Pointcut("execution(* getAge())")
    public void getAge() {
    }

    @Around("org.springframework.aop.aspectj.annotation.AbstractAspectJAdvisorFactoryTests.NamedPointcutAspectWithFQN.getAge()")
    public int changeReturnValue(ProceedingJoinPoint pjp) {
      return -1;
    }
  }


  @Aspect
  public static class NamedPointcutAspectWithoutFQN {
    @Pointcut("execution(* getAge())")
    public void getAge() {
    }

    @Around("getAge()")
    public int changeReturnValue(ProceedingJoinPoint pjp) {
      return -1;
    }
  }


  @Aspect
  public static class NamedPointcutAspectFromLibrary {

    @Around("org.springframework.aop.aspectj.annotation.AbstractAspectJAdvisorFactoryTests.Library.propertyAccess()")
    public int changeReturnType(ProceedingJoinPoint pjp) {
      return -1;
    }

    @Around(value="org.springframework.aop.aspectj.annotation.AbstractAspectJAdvisorFactoryTests.Library.integerArgOperation(x)", argNames="x")
    public void doubleArg(ProceedingJoinPoint pjp, int x) throws Throwable {
      pjp.proceed(new Object[] {x*2});
    }
  }


  @Aspect
  public static class Library {

    @Pointcut("execution(!void get*())")
    public void propertyAccess() {}

    @Pointcut("execution(* *(..)) && args(i)")
    public void integerArgOperation(int i) {}

  }


  @Aspect
  public static class NamedPointcutAspectFromLibraryWithBinding {

    @Around(value="org.springframework.aop.aspectj.annotation.AbstractAspectJAdvisorFactoryTests.Library.integerArgOperation(x)", argNames="x")
    public void doubleArg(ProceedingJoinPoint pjp, int x) throws Throwable {
      pjp.proceed(new Object[] {x*2});
    }
  }


  @Aspect
  public static class BindingAspectWithSingleArg {

    @Pointcut(value="args(a)", argNames="a")
    public void setAge(int a) {}

    @Around(value="setAge(age)",argNames="age")
    // @ArgNames({"age"})  // AMC needs more work here? ignoring pjp arg... ok??
                // argNames should be suported in Around as it is in Pointcut
    public void changeReturnType(ProceedingJoinPoint pjp, int age) throws Throwable {
      pjp.proceed(new Object[] {age*2});
    }
  }


  @Aspect
  public static class ManyValuedArgs {
    public String mungeArgs(String a, int b, int c, String d, StringBuffer e) {
      return a + b + c + d + e;
    }

    @Around(value="execution(String mungeArgs(..)) && args(a, b, c, d, e)",
        argNames="b,c,d,e,a")
    public String reverseAdvice(ProceedingJoinPoint pjp, int b, int c, String d, StringBuffer e, String a) throws Throwable {
      assertEquals(a + b+ c+ d+ e, pjp.proceed());
      return a + b + c + d + e;
    }
  }


  @Aspect
  public static class ExceptionAspect {
    private final Exception ex;

    public ExceptionAspect(Exception ex) {
      this.ex = ex;
    }

    @Before("execution(* getAge())")
    public void throwException() throws Exception {
      throw ex;
    }
  }


  public static class Echo {

    public Object echo(Object o) throws Exception {
      if (o instanceof Exception) {
        throw (Exception) o;
      }
      return o;
    }
  }


  @Aspect
  public static class ExceptionHandling {
    public int successCount;
    public int failureCount;
    public int afterCount;

    @AfterReturning("execution(* echo(*))")
    public void succeeded() {
      ++successCount;
    }

    @AfterThrowing("execution(* echo(*))")
    public void failed() {
      ++failureCount;
    }

    @After("execution(* echo(*))")
    public void invoked() {
      ++afterCount;
    }
  }


  @Aspect
  public static class NoDeclarePrecedenceShouldFail {

    @Pointcut("execution(int *.getAge())")
    public void getAge() {
    }

    @Before("getAge()")
    public void blowUpButDoesntMatterBecauseAroundAdviceWontLetThisBeInvoked() {
      throw new IllegalStateException();
    }

    @Around("getAge()")
    public int preventExecution(ProceedingJoinPoint pjp) {
      return 666;
    }
  }


  @Aspect
  @DeclarePrecedence("test..*")
  public static class DeclarePrecedenceShouldSucceed {

    @Pointcut("execution(int *.getAge())")
    public void getAge() {
    }

    @Before("getAge()")
    public void blowUpButDoesntMatterBecauseAroundAdviceWontLetThisBeInvoked() {
      throw new IllegalStateException();
    }

    @Around("getAge()")
    public int preventExecution(ProceedingJoinPoint pjp) {
      return 666;
    }
  }

}


/**
* Add a DeclareParents field in concrete subclasses, to identify
* the type pattern to apply the introduction to.
*
* @author Rod Johnson
* @since 2.0
*/
@Aspect
abstract class AbstractMakeModifiable {

  public interface MutableModifable extends Modifiable {
    void markDirty();
  }

  public static class ModifiableImpl implements MutableModifable {
    private boolean modified;

    @Override
    public void acceptChanges() {
      modified = false;
    }

    @Override
    public boolean isModified() {
      return modified;
    }

    @Override
    public void markDirty() {
      this.modified = true;
    }
  }

  @Before(value="execution(void set*(*)) && this(modifiable) && args(newValue)",
      argNames="modifiable,newValue")
  public void recordModificationIfSetterArgumentDiffersFromOldValue(JoinPoint jp,
    MutableModifable mixin, Object newValue) {

    /*
     * We use the mixin to check and, if necessary, change,
     * modification status. We need the JoinPoint to get the
     * setter method. We use newValue for comparison.
     * We try to invoke the getter if possible.
     */

    if (mixin.isModified()) {
      // Already changed, don't need to change again
      //System.out.println("changed");
      return;
    }

    // Find the current raw value, by invoking the corresponding setter
    Method correspondingGetter = getGetterFromSetter(((MethodSignature) jp.getSignature()).getMethod());
    boolean modified = true;
    if (correspondingGetter != null) {
      try {
        Object oldValue = correspondingGetter.invoke(jp.getTarget());
        //System.out.println("Old value=" + oldValue + "; new=" + newValue);
        modified = !ObjectUtils.nullSafeEquals(oldValue, newValue);
      }
      catch (Exception ex) {
        ex.printStackTrace();
        // Don't sweat on exceptions; assume value was modified
      }
    }
    else {
      //System.out.println("cannot get getter for " + jp);
    }
    if (modified) {
      mixin.markDirty();
    }
  }

  private Method getGetterFromSetter(Method setter) {
    String getterName = setter.getName().replaceFirst("set", "get");
    try {
      return setter.getDeclaringClass().getMethod(getterName, (Class[]) null);
    }
    catch (NoSuchMethodException ex) {
      // must be write only
      return null;
    }
  }

}


/**
* Adds a declare parents pointcut.
* @author Rod Johnson
* @since 2.0
*/
@Aspect
class MakeITestBeanModifiable extends AbstractMakeModifiable {

  @DeclareParents(value = "org.springframework.tests.sample.beans.ITestBean+",
      defaultImpl=ModifiableImpl.class)
  public static MutableModifable mixin;

}

/**
* Adds a declare parents pointcut - spr5307
* @author Andy Clement
* @since 3.0
*/
@Aspect
class MakeAnnotatedTypeModifiable extends AbstractMakeModifiable {

  @DeclareParents(value = "(@org.springframework.aop.aspectj.annotation.Measured *)",
//  @DeclareParents(value = "(@Measured *)", // this would be a nice alternative...
      defaultImpl=DefaultLockable.class)
  public static Lockable mixin;

}


/**
* Demonstrates introductions, AspectJ annotation style.
*/
@Aspect
class MakeLockable {

  @DeclareParents(value = "org.springframework..*",
      defaultImpl=DefaultLockable.class)
  public static Lockable mixin;

  @Before(value="execution(void set*(*)) && this(mixin)", argNames="mixin")
  public void checkNotLocked(
    Lockable mixin// Bind to arg
  {
    // Can also obtain the mixin (this) this way
    //Lockable mixin = (Lockable) jp.getThis();
    if (mixin.locked()) {
      throw new IllegalStateException();
    }
  }

}


class CannotBeUnlocked implements Lockable, Comparable<Object> {

  @Override
  public void lock() {
  }

  @Override
  public void unlock() {
    throw new UnsupportedOperationException();
  }

  @Override
  public boolean locked() {
    return true;
  }

  @Override
  public int compareTo(Object arg0) {
    throw new UnsupportedOperationException();
  }

}


/**
* Used as a mixin.
*
* @author Rod Johnson
*/
interface Modifiable {

  boolean isModified();

  void acceptChanges();

}

/**
* Used as a target.
* @author Andy Clement
*/
interface AnnotatedTarget {
}

@Measured
class AnnotatedTargetImpl implements AnnotatedTarget {

}

@Retention(RetentionPolicy.RUNTIME)
@interface Measured {}

class NotLockable {

  private int intValue;

  public int getIntValue() {
    return intValue;
  }

  public void setIntValue(int intValue) {
    this.intValue = intValue;
  }

}


@Aspect("perthis(execution(* *.getSpouse()))")
class PerThisAspect {

  public int count;

  /**
   * Just to check that this doesn't cause problems with introduction processing
   */
  private ITestBean fieldThatShouldBeIgnoredBySpringAtAspectJProcessing = new TestBean();

  @Around("execution(int *.getAge())")
  public int returnCountAsAge() {
    return count++;
  }

  @Before("execution(void *.set*(int))")
  public void countSetter() {
    ++count;
  }

}
TOP

Related Classes of org.springframework.aop.aspectj.annotation.AbstractAspectJAdvisorFactoryTests

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.