Logo Search packages:      
Sourcecode: aspectj version File versions

AnnotationPointcut.java

/* *******************************************************************
 * Copyright (c) 2004 IBM Corporation.
 * All rights reserved. 
 * This program and the accompanying materials are made available 
 * under the terms of the Eclipse Public License v1.0 
 * which accompanies this distribution and is available at 
 * http://www.eclipse.org/legal/epl-v10.html 
 *  
 * ******************************************************************/

package org.aspectj.weaver.patterns;

import java.io.DataOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import org.aspectj.bridge.MessageUtil;
import org.aspectj.util.FuzzyBoolean;
import org.aspectj.weaver.AjcMemberMaker;
import org.aspectj.weaver.AnnotatedElement;
import org.aspectj.weaver.BCException;
import org.aspectj.weaver.ConcreteTypeMunger;
import org.aspectj.weaver.ISourceContext;
import org.aspectj.weaver.IntMap;
import org.aspectj.weaver.Member;
import org.aspectj.weaver.NameMangler;
import org.aspectj.weaver.NewFieldTypeMunger;
import org.aspectj.weaver.ResolvedMember;
import org.aspectj.weaver.ResolvedType;
import org.aspectj.weaver.Shadow;
import org.aspectj.weaver.ShadowMunger;
import org.aspectj.weaver.UnresolvedType;
import org.aspectj.weaver.VersionedDataInputStream;
import org.aspectj.weaver.WeaverMessages;
import org.aspectj.weaver.World;
import org.aspectj.weaver.ast.Literal;
import org.aspectj.weaver.ast.Test;
import org.aspectj.weaver.ast.Var;

/**
 * (at)Annotation((at)Foo) or (at)Annotation(foo)<br>
 * <p>
 * Matches any join point where the subject of the join point has an annotation matching the annotationTypePattern:
 * 
 * <br>
 * Join Point Kind - Subject <br>
 * ================================ <br>
 * method call - the target method <br>
 * method execution - the method <br>
 * constructor call - the constructor <br>
 * constructor execution - the constructor <br>
 * get - the target field <br>
 * set - the target field <br>
 * adviceexecution - the advice <br>
 * initialization - the constructor <br>
 * preinitialization - the constructor <br>
 * staticinitialization - the type being initialized <br>
 * handler - the declared type of the handled exception <br>
 */
00064 public class AnnotationPointcut extends NameBindingPointcut {

      private ExactAnnotationTypePattern annotationTypePattern;
      private String declarationText;

      public AnnotationPointcut(ExactAnnotationTypePattern type) {
            super();
            this.annotationTypePattern = type;
            this.pointcutKind = Pointcut.ANNOTATION;
            buildDeclarationText();
      }

      public AnnotationPointcut(ExactAnnotationTypePattern type, ShadowMunger munger) {
            this(type);
            buildDeclarationText();
      }

      public ExactAnnotationTypePattern getAnnotationTypePattern() {
            return annotationTypePattern;
      }

00085       public int couldMatchKinds() {
            return Shadow.ALL_SHADOW_KINDS_BITS;
      }

      public Pointcut parameterizeWith(Map typeVariableMap, World w) {
            AnnotationPointcut ret = new AnnotationPointcut((ExactAnnotationTypePattern) annotationTypePattern.parameterizeWith(
                        typeVariableMap, w));
            ret.copyLocationFrom(this);
            return ret;
      }

      /*
       * (non-Javadoc)
       * 
       * @see org.aspectj.weaver.patterns.Pointcut#fastMatch(org.aspectj.weaver.patterns.FastMatchInfo)
       */
00101       public FuzzyBoolean fastMatch(FastMatchInfo info) {
            if (info.getKind() == Shadow.StaticInitialization) {
                  return annotationTypePattern.fastMatches(info.getType());
            } else {
                  return FuzzyBoolean.MAYBE;
            }
      }

      /*
       * (non-Javadoc)
       * 
       * @see org.aspectj.weaver.patterns.Pointcut#match(org.aspectj.weaver.Shadow)
       */
      protected FuzzyBoolean matchInternal(Shadow shadow) {
            AnnotatedElement toMatchAgainst = null;
            Member member = shadow.getSignature();
            ResolvedMember rMember = member.resolve(shadow.getIWorld());

            if (rMember == null) {
                  if (member.getName().startsWith(NameMangler.PREFIX)) {
                        return FuzzyBoolean.NO;
                  }
                  shadow.getIWorld().getLint().unresolvableMember.signal(member.toString(), getSourceLocation());
                  return FuzzyBoolean.NO;
            }

            Shadow.Kind kind = shadow.getKind();
            if (kind == Shadow.StaticInitialization) {
                  toMatchAgainst = rMember.getDeclaringType().resolve(shadow.getIWorld());
            } else if ((kind == Shadow.ExceptionHandler)) {
                  toMatchAgainst = rMember.getParameterTypes()[0].resolve(shadow.getIWorld());
            } else {
                  toMatchAgainst = rMember;
                  // FIXME asc I'd like to get rid of this bit of logic altogether, shame ITD fields don't have an effective sig attribute
                  // FIXME asc perf cache the result of discovering the member that contains the real annotations
                  if (rMember.isAnnotatedElsewhere()) {
                        if (kind == Shadow.FieldGet || kind == Shadow.FieldSet) {
                              // FIXME asc should include supers with getInterTypeMungersIncludingSupers ?
                              List mungers = rMember.getDeclaringType().resolve(shadow.getIWorld()).getInterTypeMungers();
                              for (Iterator iter = mungers.iterator(); iter.hasNext();) {
                                    ConcreteTypeMunger typeMunger = (ConcreteTypeMunger) iter.next();
                                    if (typeMunger.getMunger() instanceof NewFieldTypeMunger) {
                                          ResolvedMember fakerm = typeMunger.getSignature();
                                          if (fakerm.equals(member)) {
                                                ResolvedMember ajcMethod = AjcMemberMaker.interFieldInitializer(fakerm, typeMunger.getAspectType());
                                                ResolvedMember rmm = findMethod(typeMunger.getAspectType(), ajcMethod);
                                                toMatchAgainst = rmm;
                                          }
                                    }
                              }
                        }
                  }
            }

            annotationTypePattern.resolve(shadow.getIWorld());
            return annotationTypePattern.matches(toMatchAgainst);
      }

      private ResolvedMember findMethod(ResolvedType aspectType, ResolvedMember ajcMethod) {
            ResolvedMember decMethods[] = aspectType.getDeclaredMethods();
            for (int i = 0; i < decMethods.length; i++) {
                  ResolvedMember member = decMethods[i];
                  if (member.equals(ajcMethod))
                        return member;
            }
            return null;
      }

      /*
       * (non-Javadoc)
       * 
       * @see org.aspectj.weaver.patterns.Pointcut#resolveBindings(org.aspectj.weaver.patterns.IScope,
       * org.aspectj.weaver.patterns.Bindings)
       */
      protected void resolveBindings(IScope scope, Bindings bindings) {
            if (!scope.getWorld().isInJava5Mode()) {
                  scope.message(MessageUtil.error(WeaverMessages.format(WeaverMessages.ATANNOTATION_ONLY_SUPPORTED_AT_JAVA5_LEVEL),
                              getSourceLocation()));
                  return;
            }
            annotationTypePattern = (ExactAnnotationTypePattern) annotationTypePattern.resolveBindings(scope, bindings, true);
            // must be either a Var, or an annotation type pattern
      }

      /*
       * (non-Javadoc)
       * 
       * @see org.aspectj.weaver.patterns.Pointcut#concretize1(org.aspectj.weaver.ResolvedType, org.aspectj.weaver.IntMap)
       */
00190       protected Pointcut concretize1(ResolvedType inAspect, ResolvedType declaringType, IntMap bindings) {
            ExactAnnotationTypePattern newType = (ExactAnnotationTypePattern) annotationTypePattern.remapAdviceFormals(bindings);
            Pointcut ret = new AnnotationPointcut(newType, bindings.getEnclosingAdvice());
            ret.copyLocationFrom(this);
            return ret;
      }

      protected Test findResidueInternal(Shadow shadow, ExposedState state) {
            if (annotationTypePattern instanceof BindingAnnotationFieldTypePattern) {
                  if (shadow.getKind() != Shadow.MethodExecution) {
                        shadow.getIWorld().getMessageHandler().handleMessage(
                                    MessageUtil.error(
                                                "Annotation field binding is only supported at method-execution join points (compiler limitation)",
                                                getSourceLocation()));
                        return Literal.TRUE; // exit quickly, error will prevent weaving
                  }
                  BindingAnnotationFieldTypePattern btp = (BindingAnnotationFieldTypePattern) annotationTypePattern;
                  ResolvedType formalType = btp.getFormalType().resolve(shadow.getIWorld());
                  UnresolvedType annoType = btp.getAnnotationType();
                  // TODO 2 need to sort out appropriate creation of the AnnotationAccessFieldVar - what happens for
                  // reflective (ReflectionShadow) access to types?
                  Var var = shadow.getKindedAnnotationVar(annoType);
                  if (var == null) {
                        throw new BCException("Unexpected problem locating annotation at join point '" + shadow + "'");
                  }
                  state.set(btp.getFormalIndex(), var.getAccessorForValue(formalType));
            } else if (annotationTypePattern instanceof BindingAnnotationTypePattern) {
                  BindingAnnotationTypePattern btp = (BindingAnnotationTypePattern) annotationTypePattern;
                  UnresolvedType annotationType = btp.getAnnotationType();
                  Var var = shadow.getKindedAnnotationVar(annotationType);

                  // At this point, var *could* be null. The only reason this could happen (if we aren't failing...)
                  // is if another binding annotation designator elsewhere in the pointcut is going to expose the annotation
                  // eg. (execution(* a*(..)) && @annotation(foo)) || (execution(* b*(..)) && @this(foo))
                  // where sometimes @annotation will be providing the value, and sometimes
                  // @this will be providing the value (see pr138223)

                  // If we are here for other indecipherable reasons (it's not the case above...) then
                  // you might want to uncomment this next bit of code to collect the diagnostics
                  // if (var == null) throw new BCException("Impossible! annotation=["+annotationType+
                  // "]  shadow=["+shadow+" at "+shadow.getSourceLocation()+
                  // "]    pointcut is at ["+getSourceLocation()+"]");
                  if (var == null) {
                        if (matchInternal(shadow).alwaysTrue())
                              return Literal.TRUE;
                        else
                              return Literal.FALSE;
                  }
                  state.set(btp.getFormalIndex(), var);
            }

            if (matchInternal(shadow).alwaysTrue())
                  return Literal.TRUE;
            else
                  return Literal.FALSE;
      }

      /*
       * (non-Javadoc)
       * 
       * @see org.aspectj.weaver.patterns.NameBindingPointcut#getBindingAnnotationTypePatterns()
       */
      public List getBindingAnnotationTypePatterns() {
            if (annotationTypePattern instanceof BindingPattern) { // BindingAnnotationTypePattern) {
                  List l = new ArrayList();
                  l.add(annotationTypePattern);
                  return l;
            } else
                  return Collections.EMPTY_LIST;
      }

      /*
       * (non-Javadoc)
       * 
       * @see org.aspectj.weaver.patterns.NameBindingPointcut#getBindingTypePatterns()
       */
      public List getBindingTypePatterns() {
            return Collections.EMPTY_LIST;
      }

      /*
       * (non-Javadoc)
       * 
       * @see org.aspectj.weaver.patterns.PatternNode#write(java.io.DataOutputStream)
       */
      public void write(DataOutputStream s) throws IOException {
            s.writeByte(Pointcut.ANNOTATION);
            annotationTypePattern.write(s);
            writeLocation(s);
      }

      public static Pointcut read(VersionedDataInputStream s, ISourceContext context) throws IOException {
            AnnotationTypePattern type = AnnotationTypePattern.read(s, context);
            AnnotationPointcut ret = new AnnotationPointcut((ExactAnnotationTypePattern) type);
            ret.readLocation(context, s);
            return ret;
      }

      public boolean equals(Object other) {
            if (!(other instanceof AnnotationPointcut))
                  return false;
            AnnotationPointcut o = (AnnotationPointcut) other;
            return o.annotationTypePattern.equals(this.annotationTypePattern);
      }

      public int hashCode() {
            int result = 17;
            result = 37 * result + annotationTypePattern.hashCode();
            return result;
      }

      public void buildDeclarationText() {
            StringBuffer buf = new StringBuffer();
            buf.append("@annotation(");
            String annPatt = annotationTypePattern.toString();
            buf.append(annPatt.startsWith("@") ? annPatt.substring(1) : annPatt);
            buf.append(")");
            this.declarationText = buf.toString();
      }

      public String toString() {
            return this.declarationText;
      }

      public Object accept(PatternNodeVisitor visitor, Object data) {
            return visitor.visit(this, data);
      }

}

Generated by  Doxygen 1.6.0   Back to index