Package org.springframework.aop.aspectj.annotation

Source Code of org.springframework.aop.aspectj.annotation.ReflectiveAspectJAdvisorFactory$SyntheticInstantiationAdvisor

/*
* Copyright 2002-2012 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.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Collections;
import java.util.Comparator;
import java.util.LinkedList;
import java.util.List;

import org.aopalliance.aop.Advice;
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.Before;
import org.aspectj.lang.annotation.DeclareParents;
import org.aspectj.lang.annotation.Pointcut;

import org.springframework.aop.Advisor;
import org.springframework.aop.MethodBeforeAdvice;
import org.springframework.aop.aspectj.AbstractAspectJAdvice;
import org.springframework.aop.aspectj.AspectJAfterAdvice;
import org.springframework.aop.aspectj.AspectJAfterReturningAdvice;
import org.springframework.aop.aspectj.AspectJAfterThrowingAdvice;
import org.springframework.aop.aspectj.AspectJAroundAdvice;
import org.springframework.aop.aspectj.AspectJExpressionPointcut;
import org.springframework.aop.aspectj.AspectJMethodBeforeAdvice;
import org.springframework.aop.aspectj.DeclareParentsAdvisor;
import org.springframework.aop.framework.AopConfigException;
import org.springframework.aop.support.DefaultPointcutAdvisor;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.core.convert.converter.Converter;
import org.springframework.core.convert.converter.ConvertingComparator;
import org.springframework.util.ReflectionUtils;
import org.springframework.util.StringUtils;
import org.springframework.util.comparator.CompoundComparator;
import org.springframework.util.comparator.InstanceComparator;

/**
* Factory that can create Spring AOP Advisors given AspectJ classes from
* classes honoring the AspectJ 5 annotation syntax, using reflection to
* invoke the corresponding advice methods.
*
* @author Rod Johnson
* @author Adrian Colyer
* @author Juergen Hoeller
* @author Ramnivas Laddad
* @author Phillip Webb
* @since 2.0
*/
public class ReflectiveAspectJAdvisorFactory extends AbstractAspectJAdvisorFactory {

  private static final Comparator<Method> METHOD_COMPARATOR;

  static {
    CompoundComparator<Method> comparator = new CompoundComparator<Method>();
    comparator.addComparator(new ConvertingComparator<Method, Annotation>(
        new InstanceComparator<Annotation>(
            Around.class, Before.class, After.class, AfterReturning.class, AfterThrowing.class),
        new Converter<Method, Annotation>() {
          public Annotation convert(Method method) {
            AspectJAnnotation<?> annotation = AbstractAspectJAdvisorFactory.findAspectJAnnotationOnMethod(method);
            return annotation == null ? null : annotation.getAnnotation();
          }
        }));
    comparator.addComparator(new ConvertingComparator<Method, String>(
        new Converter<Method, String>() {
          public String convert(Method method) {
            return method.getName();
          }
        }));
    METHOD_COMPARATOR = comparator;
  }


  public List<Advisor> getAdvisors(MetadataAwareAspectInstanceFactory maaif) {
    final Class<?> aspectClass = maaif.getAspectMetadata().getAspectClass();
    final String aspectName = maaif.getAspectMetadata().getAspectName();
    validate(aspectClass);

    // We need to wrap the MetadataAwareAspectInstanceFactory with a decorator
    // so that it will only instantiate once.
    final MetadataAwareAspectInstanceFactory lazySingletonAspectInstanceFactory =
        new LazySingletonAspectInstanceFactoryDecorator(maaif);

    final List<Advisor> advisors = new LinkedList<Advisor>();
    for (Method method : getAdvisorMethods(aspectClass)) {
      Advisor advisor = getAdvisor(method, lazySingletonAspectInstanceFactory, advisors.size(), aspectName);
      if (advisor != null) {
        advisors.add(advisor);
      }
    }

    // If it's a per target aspect, emit the dummy instantiating aspect.
    if (!advisors.isEmpty() && lazySingletonAspectInstanceFactory.getAspectMetadata().isLazilyInstantiated()) {
      Advisor instantiationAdvisor = new SyntheticInstantiationAdvisor(lazySingletonAspectInstanceFactory);
      advisors.add(0, instantiationAdvisor);
    }

    // Find introduction fields.
    for (Field field : aspectClass.getDeclaredFields()) {
      Advisor advisor = getDeclareParentsAdvisor(field);
      if (advisor != null) {
        advisors.add(advisor);
      }
    }

    return advisors;
  }

  private List<Method> getAdvisorMethods(Class<?> aspectClass) {
    final List<Method> methods = new LinkedList<Method>();
    ReflectionUtils.doWithMethods(aspectClass, new ReflectionUtils.MethodCallback() {
      public void doWith(Method method) throws IllegalArgumentException {
        // Exclude pointcuts
        if (AnnotationUtils.getAnnotation(method, Pointcut.class) == null) {
          methods.add(method);
        }
      }
    });
    Collections.sort(methods, METHOD_COMPARATOR);
    return methods;
  }

  /**
   * Build a {@link org.springframework.aop.aspectj.DeclareParentsAdvisor}
   * for the given introduction field.
   * <p>Resulting Advisors will need to be evaluated for targets.
   * @param introductionField the field to introspect
   * @return <code>null</code> if not an Advisor
   */
  private Advisor getDeclareParentsAdvisor(Field introductionField) {
    DeclareParents declareParents = introductionField.getAnnotation(DeclareParents.class);
    if (declareParents == null) {
      // Not an introduction field
      return null;
    }

    if (DeclareParents.class.equals(declareParents.defaultImpl())) {
      // This is what comes back if it wasn't set. This seems bizarre...
      // TODO this restriction possibly should be relaxed
      throw new IllegalStateException("defaultImpl must be set on DeclareParents");
    }

    return new DeclareParentsAdvisor(
        introductionField.getType(), declareParents.value(), declareParents.defaultImpl());
  }


  public Advisor getAdvisor(Method candidateAdviceMethod, MetadataAwareAspectInstanceFactory aif,
      int declarationOrderInAspect, String aspectName) {

    validate(aif.getAspectMetadata().getAspectClass());

    AspectJExpressionPointcut ajexp =
        getPointcut(candidateAdviceMethod, aif.getAspectMetadata().getAspectClass());
    if (ajexp == null) {
      return null;
    }
    return new InstantiationModelAwarePointcutAdvisorImpl(
        this, ajexp, aif, candidateAdviceMethod, declarationOrderInAspect, aspectName);
  }

  private AspectJExpressionPointcut getPointcut(Method candidateAdviceMethod, Class<?> candidateAspectClass) {
    AspectJAnnotation<?> aspectJAnnotation =
        AbstractAspectJAdvisorFactory.findAspectJAnnotationOnMethod(candidateAdviceMethod);
    if (aspectJAnnotation == null) {
      return null;
    }
    AspectJExpressionPointcut ajexp =
        new AspectJExpressionPointcut(candidateAspectClass, new String[0], new Class[0]);
    ajexp.setExpression(aspectJAnnotation.getPointcutExpression());
    return ajexp;
  }


  public Advice getAdvice(Method candidateAdviceMethod, AspectJExpressionPointcut ajexp,
      MetadataAwareAspectInstanceFactory aif, int declarationOrderInAspect, String aspectName) {

    Class<?> candidateAspectClass = aif.getAspectMetadata().getAspectClass();
    validate(candidateAspectClass);

    AspectJAnnotation<?> aspectJAnnotation =
        AbstractAspectJAdvisorFactory.findAspectJAnnotationOnMethod(candidateAdviceMethod);
    if (aspectJAnnotation == null) {
      return null;
    }

    // If we get here, we know we have an AspectJ method.
    // Check that it's an AspectJ-annotated class
    if (!isAspect(candidateAspectClass)) {
      throw new AopConfigException("Advice must be declared inside an aspect type: " +
          "Offending method '" + candidateAdviceMethod + "' in class [" +
          candidateAspectClass.getName() + "]");
    }

    if (logger.isDebugEnabled()) {
      logger.debug("Found AspectJ method: " + candidateAdviceMethod);
    }

    AbstractAspectJAdvice springAdvice;

    switch (aspectJAnnotation.getAnnotationType()) {
      case AtBefore:
        springAdvice = new AspectJMethodBeforeAdvice(candidateAdviceMethod, ajexp, aif);
        break;
      case AtAfter:
        springAdvice = new AspectJAfterAdvice(candidateAdviceMethod, ajexp, aif);
        break;
      case AtAfterReturning:
        springAdvice = new AspectJAfterReturningAdvice(candidateAdviceMethod, ajexp, aif);
        AfterReturning afterReturningAnnotation = (AfterReturning) aspectJAnnotation.getAnnotation();
        if (StringUtils.hasText(afterReturningAnnotation.returning())) {
          springAdvice.setReturningName(afterReturningAnnotation.returning());
        }
        break;
      case AtAfterThrowing:
        springAdvice = new AspectJAfterThrowingAdvice(candidateAdviceMethod, ajexp, aif);
        AfterThrowing afterThrowingAnnotation = (AfterThrowing) aspectJAnnotation.getAnnotation();
        if (StringUtils.hasText(afterThrowingAnnotation.throwing())) {
          springAdvice.setThrowingName(afterThrowingAnnotation.throwing());
        }
        break;
      case AtAround:
        springAdvice = new AspectJAroundAdvice(candidateAdviceMethod, ajexp, aif);
        break;
      case AtPointcut:
        if (logger.isDebugEnabled()) {
          logger.debug("Processing pointcut '" + candidateAdviceMethod.getName() + "'");
        }
        return null;
      default:
        throw new UnsupportedOperationException(
            "Unsupported advice type on method " + candidateAdviceMethod);
    }

    // Now to configure the advice...
    springAdvice.setAspectName(aspectName);
    springAdvice.setDeclarationOrder(declarationOrderInAspect);
    String[] argNames = this.parameterNameDiscoverer.getParameterNames(candidateAdviceMethod);
    if (argNames != null) {
      springAdvice.setArgumentNamesFromStringArray(argNames);
    }
    springAdvice.calculateArgumentBindings();
    return springAdvice;
  }

  /**
   * Synthetic advisor that instantiates the aspect.
   * Triggered by per-clause pointcut on non-singleton aspect.
   * The advice has no effect.
   */
  @SuppressWarnings("serial")
  protected static class SyntheticInstantiationAdvisor extends DefaultPointcutAdvisor {

    public SyntheticInstantiationAdvisor(final MetadataAwareAspectInstanceFactory aif) {
      super(aif.getAspectMetadata().getPerClausePointcut(), new MethodBeforeAdvice() {
        public void before(Method method, Object[] args, Object target) {
          // Simply instantiate the aspect
          aif.getAspectInstance();
        }
      });
    }
  }

}
TOP

Related Classes of org.springframework.aop.aspectj.annotation.ReflectiveAspectJAdvisorFactory$SyntheticInstantiationAdvisor

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.