]> source.dussan.org Git - aspectj.git/commitdiff
annoValMatch: implementation
authoraclement <aclement>
Mon, 25 Feb 2008 22:10:36 +0000 (22:10 +0000)
committeraclement <aclement>
Mon, 25 Feb 2008 22:10:36 +0000 (22:10 +0000)
weaver/src/org/aspectj/weaver/patterns/ExactAnnotationTypePattern.java
weaver/src/org/aspectj/weaver/patterns/WildAnnotationTypePattern.java

index 060d2956ae945e32cb00918ea7325c720803f59b..0dafaedd7e2cc4d6d4f3098c66643e700bd8aef2 100644 (file)
@@ -11,15 +11,20 @@ package org.aspectj.weaver.patterns;
 
 import java.io.DataOutputStream;
 import java.io.IOException;
+import java.util.HashMap;
+import java.util.Iterator;
 import java.util.Map;
+import java.util.Set;
 
 import org.aspectj.bridge.IMessage;
 import org.aspectj.bridge.MessageUtil;
 import org.aspectj.util.FuzzyBoolean;
 import org.aspectj.weaver.AnnotatedElement;
+import org.aspectj.weaver.AnnotationX;
 import org.aspectj.weaver.BCException;
 import org.aspectj.weaver.ISourceContext;
 import org.aspectj.weaver.ReferenceType;
+import org.aspectj.weaver.ResolvedMember;
 import org.aspectj.weaver.ResolvedType;
 import org.aspectj.weaver.TypeVariableReference;
 import org.aspectj.weaver.UnresolvedType;
@@ -37,11 +42,20 @@ public class ExactAnnotationTypePattern extends AnnotationTypePattern {
        protected String formalName;
        protected boolean resolved = false;
        private boolean bindingPattern = false;
+       private Map annotationValues;
        
        /**
+        * @param annotationValues 
         * 
         */
-       public ExactAnnotationTypePattern(UnresolvedType annotationType) {
+       public ExactAnnotationTypePattern(UnresolvedType annotationType, Map annotationValues) {
+               this.annotationType = annotationType;
+               this.annotationValues = annotationValues;
+               this.resolved = (annotationType instanceof ResolvedType);
+       }
+       
+       // Used when deserializing, values will be added
+       private ExactAnnotationTypePattern(UnresolvedType annotationType) {
                this.annotationType = annotationType;
                this.resolved = (annotationType instanceof ResolvedType);
        }
@@ -61,9 +75,13 @@ public class ExactAnnotationTypePattern extends AnnotationTypePattern {
     public UnresolvedType getAnnotationType() {
         return annotationType;
     }
+    
+    public Map getAnnotationValues() {
+       return annotationValues;
+    }
 
        public FuzzyBoolean fastMatches(AnnotatedElement annotated) {
-               if (annotated.hasAnnotation(annotationType)) {
+               if (annotated.hasAnnotation(annotationType) && annotationValues == null) {
                        return FuzzyBoolean.YES;
                } else {
                        // could be inherited, but we don't know that until we are 
@@ -94,11 +112,73 @@ public class ExactAnnotationTypePattern extends AnnotationTypePattern {
                                                return FuzzyBoolean.NO;
                                        }
                                }
+                               
+                               
+                               // Are we also matching annotation values?
+                               if (annotationValues!=null) {
+                                       AnnotationX theAnnotation = annotated.getAnnotationOfType(annotationType);
+                                       
+                                       // Check each one
+                                       Set keys = annotationValues.keySet();
+                                       for (Iterator keyIter = keys.iterator(); keyIter.hasNext();) {
+                                               String k = (String) keyIter.next();
+                                               String v = (String)annotationValues.get(k);
+                                               if (theAnnotation.hasNamedValue(k)) {
+                                                       // Simple case, value is 'name=value' and the annotation specified the same thing
+                                                       if (!theAnnotation.hasNameValuePair(k,v)) {
+                                                               return FuzzyBoolean.NO;
+                                                       }       
+                                               } else {
+                                                       // Complex case, look at the default value
+                                                       ResolvedMember[] ms = ((ResolvedType)annotationType).getDeclaredMethods();
+                                                       boolean foundMatch = false;
+                                                       for (int i=0; i<ms.length && !foundMatch;i++) {
+                                                               if (ms[i].isAbstract() && ms[i].getParameterTypes().length==0 && ms[i].getName().equals(k)) {
+                                                                       // we might be onto something
+                                                                       String s= ms[i].getAnnotationDefaultValue();
+                                                                       if (s!=null && s.equals(v)) foundMatch=true;;
+                                                               }
+                                                       }
+                                                       if (!foundMatch)
+                                                       return FuzzyBoolean.NO;
+                                               }
+                                       }
+                               }
                                return FuzzyBoolean.YES;
                        } else if (checkSupers) {
                                ResolvedType toMatchAgainst = ((ResolvedType) annotated).getSuperclass();
                                while (toMatchAgainst != null) {
                                        if (toMatchAgainst.hasAnnotation(annotationType)) {
+                                               // Are we also matching annotation values?
+                                               if (annotationValues!=null) {
+                                                       AnnotationX theAnnotation = toMatchAgainst.getAnnotationOfType(annotationType);
+                                                       
+                                                       // Check each one
+                                                       Set keys = annotationValues.keySet();
+                                                       for (Iterator keyIter = keys.iterator(); keyIter.hasNext();) {
+                                                               String k = (String) keyIter.next();
+                                                               String v = (String)annotationValues.get(k);
+                                                               if (theAnnotation.hasNamedValue(k)) {
+                                                                       // Simple case, value is 'name=value' and the annotation specified the same thing
+                                                                       if (!theAnnotation.hasNameValuePair(k,v)) {
+                                                                               return FuzzyBoolean.NO;
+                                                                       }       
+                                                               } else {
+                                                                       // Complex case, look at the default value
+                                                                       ResolvedMember[] ms = ((ResolvedType)annotationType).getDeclaredMethods();
+                                                                       boolean foundMatch = false;
+                                                                       for (int i=0; i<ms.length && !foundMatch;i++) {
+                                                                               if (ms[i].isAbstract() && ms[i].getParameterTypes().length==0 && ms[i].getName().equals(k)) {
+                                                                                       // we might be onto something
+                                                                                       String s= ms[i].getAnnotationDefaultValue();
+                                                                                       if (s!=null && s.equals(v)) foundMatch=true;;
+                                                                               }
+                                                                       }
+                                                                       if (!foundMatch)
+                                                                       return FuzzyBoolean.NO;
+                                                               }
+                                                       }
+                                               }
                                                return FuzzyBoolean.YES;
                                        }
                                        toMatchAgainst = toMatchAgainst.getSuperclass();
@@ -109,6 +189,12 @@ public class ExactAnnotationTypePattern extends AnnotationTypePattern {
                        if (parameterAnnotations==null) return FuzzyBoolean.NO;
                        for (int i = 0; i < parameterAnnotations.length; i++) {
                                if (annotationType.equals(parameterAnnotations[i])) {
+                                       // Are we also matching annotation values?
+                                       if (annotationValues!=null) {
+                                               parameterAnnotations[i].getWorld().getMessageHandler().handleMessage(
+                                                               MessageUtil.error("Compiler limitation: annotation value matching for parameter annotations not yet supported"));
+                                               return FuzzyBoolean.NO;
+                                       }
                                        return FuzzyBoolean.YES;
                                }
                        }
@@ -132,7 +218,9 @@ public class ExactAnnotationTypePattern extends AnnotationTypePattern {
 
        
        public void resolve(World world) {
-               if (!resolved) annotationType = annotationType.resolve(world);
+               if (!resolved) {
+                       annotationType = annotationType.resolve(world);
+               }
                resolved = true;
        }
 
@@ -199,7 +287,7 @@ public class ExactAnnotationTypePattern extends AnnotationTypePattern {
                } else if (annotationType.isParameterizedType()) {
                        newAnnotationType = annotationType.parameterize(typeVariableMap);
                }
-               ExactAnnotationTypePattern ret = new ExactAnnotationTypePattern(newAnnotationType);
+               ExactAnnotationTypePattern ret = new ExactAnnotationTypePattern(newAnnotationType,annotationValues);
                ret.formalName = formalName;
                ret.bindingPattern = bindingPattern;
                ret.copyLocationFrom(this);
@@ -241,10 +329,21 @@ public class ExactAnnotationTypePattern extends AnnotationTypePattern {
                }
                writeLocation(s);
                s.writeBoolean(isForParameterAnnotationMatch());
+               if (annotationValues==null) {
+                       s.writeInt(0);
+               } else {
+                       s.writeInt(annotationValues.size());
+                       Set key = annotationValues.keySet();
+                       for (Iterator keys = key.iterator(); keys.hasNext();) {
+                               String k = (String) keys.next();
+                               s.writeUTF(k);
+                               s.writeUTF((String)annotationValues.get(k));
+                       }
+               }
        }
 
        public static AnnotationTypePattern read(VersionedDataInputStream s,ISourceContext context) throws IOException {
-               AnnotationTypePattern ret;
+               ExactAnnotationTypePattern ret;
                byte version = s.readByte();
                if (version > VERSION) {
                        throw new BCException("ExactAnnotationTypePattern was written by a newer version of AspectJ");
@@ -259,6 +358,18 @@ public class ExactAnnotationTypePattern extends AnnotationTypePattern {
                if (s.getMajorVersion()>=WeaverVersionInfo.WEAVER_VERSION_MAJOR_AJ160) {
                        if (s.readBoolean()) ret.setForParameterAnnotationMatch();
                }
+               if (s.getMajorVersion()>=WeaverVersionInfo.WEAVER_VERSION_MAJOR_AJ160M2) {
+                       int annotationValueCount = s.readInt();
+                       if (annotationValueCount>0) {
+                               Map aValues = new HashMap();
+                               for (int i=0;i<annotationValueCount;i++) {
+                                       String key = s.readUTF();
+                                       String val = s.readUTF();
+                                       aValues.put(key,val);
+                               }
+                               ret.annotationValues = aValues;
+                       }
+               }
                return ret;
        }
        
index 2aa7c51f1de11908ed824aa8edfe3e6fa30534a8..d3fbcccfbe4903ce8c6959fce0391a8c3b55bb4d 100644 (file)
@@ -11,7 +11,10 @@ package org.aspectj.weaver.patterns;
 
 import java.io.DataOutputStream;
 import java.io.IOException;
+import java.util.HashMap;
+import java.util.Iterator;
 import java.util.Map;
+import java.util.Set;
 
 import org.aspectj.bridge.IMessage;
 import org.aspectj.bridge.MessageUtil;
@@ -19,6 +22,7 @@ import org.aspectj.util.FuzzyBoolean;
 import org.aspectj.weaver.AnnotatedElement;
 import org.aspectj.weaver.BCException;
 import org.aspectj.weaver.ISourceContext;
+import org.aspectj.weaver.ResolvedMember;
 import org.aspectj.weaver.ResolvedType;
 import org.aspectj.weaver.VersionedDataInputStream;
 import org.aspectj.weaver.WeaverMessages;
@@ -35,6 +39,7 @@ public class WildAnnotationTypePattern extends AnnotationTypePattern {
 
        private TypePattern typePattern;
        private boolean resolved = false;
+       Map annotationValues;
        
        /**
         * 
@@ -44,11 +49,19 @@ public class WildAnnotationTypePattern extends AnnotationTypePattern {
                this.typePattern = typePattern;
                this.setLocation(typePattern.getSourceContext(), typePattern.start, typePattern.end);
        }
+       
+       public WildAnnotationTypePattern(TypePattern typePattern, Map annotationValues) {
+               super();
+               this.typePattern = typePattern;
+               this.annotationValues = annotationValues;
+               // PVAL make the location be from start of type pattern to end of values
+               this.setLocation(typePattern.getSourceContext(), typePattern.start, typePattern.end);           
+       }
 
     public TypePattern getTypePattern() {
         return typePattern;
     }
-
+    
        /* (non-Javadoc)
         * @see org.aspectj.weaver.patterns.AnnotationTypePattern#matches(org.aspectj.weaver.AnnotatedElement)
         */
@@ -56,10 +69,152 @@ public class WildAnnotationTypePattern extends AnnotationTypePattern {
                return matches(annotated,null);
        }
 
+       /**
+        * Resolve any annotation values specified, checking they are all well formed (valid names, valid values)
+        * @param annotationType the annotation type for which the values have been specified
+        * @param scope the scope within which to resolve type references (eg. Color.GREEN)
+        */
+       protected void resolveAnnotationValues(ResolvedType annotationType, IScope scope) {
+               if (annotationValues == null) return;
+               // Check any values specified are OK:
+               // - the value names are for valid annotation fields
+               // - the specified values are of the correct type
+               // - for enums, check the specified values can be resolved in the specified scope
+               Set keys = annotationValues.keySet();
+               ResolvedMember[] ms = annotationType.getDeclaredMethods();
+               for (Iterator kIter = keys.iterator(); kIter.hasNext();) {
+                       String k = (String) kIter.next();
+                       String v = (String) annotationValues.get(k);
+                       boolean validKey = false;
+                       for (int i = 0; i < ms.length; i++) {
+                               ResolvedMember resolvedMember = ms[i];
+                               if (resolvedMember.getName().equals(k) && resolvedMember.isAbstract()) {
+                                       validKey = true;
+                                       ResolvedType t = resolvedMember.getReturnType().resolve(scope.getWorld());
+                                       if (t.isEnum()) {
+                                               // value must be an enum reference X.Y
+                                               int pos = v.lastIndexOf(".");
+                                               if (pos == -1) {
+                                                       IMessage m = MessageUtil.error(
+                                                                       WeaverMessages.format(WeaverMessages.INVALID_ANNOTATION_VALUE,v,"enum"),
+                                                                       getSourceLocation());
+                                                       scope.getWorld().getMessageHandler().handleMessage(m);                                                  
+                                               } else {
+                                                       String typename = v.substring(0,pos);
+                                                       ResolvedType rt = scope.lookupType(typename, this).resolve(scope.getWorld());
+                                                       v = rt.getSignature()+v.substring(pos+1); // from 'Color.RED' to 'Lp/Color;RED'
+                                                       annotationValues.put(k,v);
+                                               }
+                                       } else if (t.isPrimitiveType()) {
+                                               if (t.getSignature()=="I") {
+                                                  try {
+                                                          Integer value = Integer.parseInt(v);
+                                                          annotationValues.put(k,value.toString());
+                                                  } catch (NumberFormatException nfe) {
+                                                          IMessage m = MessageUtil.error(
+                                                                               WeaverMessages.format(WeaverMessages.INVALID_ANNOTATION_VALUE,v,"int"),
+                                                                               getSourceLocation());
+                                                               scope.getWorld().getMessageHandler().handleMessage(m);  
+                                                  }
+                                               } else if (t.getSignature()=="F") {
+                                                          try {
+                                                                  Float value = Float.parseFloat(v);
+                                                                  annotationValues.put(k,value.toString());
+                                                          } catch (NumberFormatException nfe) {
+                                                                  IMessage m = MessageUtil.error(
+                                                                                       WeaverMessages.format(WeaverMessages.INVALID_ANNOTATION_VALUE,v,"float"),
+                                                                                       getSourceLocation());
+                                                                       scope.getWorld().getMessageHandler().handleMessage(m);  
+                                                          }    
+
+                                               } else if (t.getSignature()=="Z") {
+                                                       if (v.equalsIgnoreCase("true") || v.equalsIgnoreCase("false")) {
+                                                               // is it ok !
+                                                       } else {
+                                                                  IMessage m = MessageUtil.error(
+                                                                                       WeaverMessages.format(WeaverMessages.INVALID_ANNOTATION_VALUE,v,"boolean"),
+                                                                                       getSourceLocation());
+                                                                       scope.getWorld().getMessageHandler().handleMessage(m);  
+                                                  }    
+                                               } else if (t.getSignature()=="S") {
+                                                                  try {
+                                                                          Short value = Short.parseShort(v);
+                                                                          annotationValues.put(k,value.toString());
+                                                                  } catch (NumberFormatException nfe) {
+                                                                          IMessage m = MessageUtil.error(
+                                                                                               WeaverMessages.format(WeaverMessages.INVALID_ANNOTATION_VALUE,v,"short"),
+                                                                                               getSourceLocation());
+                                                                               scope.getWorld().getMessageHandler().handleMessage(m);  
+                                                                  }
+                                               } else if (t.getSignature()=="J") {
+                                                          try {
+                                                                  Long value = Long.parseLong(v);
+                                                                  annotationValues.put(k,value.toString());
+                                                          } catch (NumberFormatException nfe) {
+                                                                  IMessage m = MessageUtil.error(
+                                                                                       WeaverMessages.format(WeaverMessages.INVALID_ANNOTATION_VALUE,v,"long"),
+                                                                                       getSourceLocation());
+                                                                       scope.getWorld().getMessageHandler().handleMessage(m);  
+                                                          }
+                                               } else if (t.getSignature()=="D") {
+                                                          try {
+                                                                  Double value = Double.parseDouble(v);
+                                                                  annotationValues.put(k,value.toString());
+                                                          } catch (NumberFormatException nfe) {
+                                                                  IMessage m = MessageUtil.error(
+                                                                                       WeaverMessages.format(WeaverMessages.INVALID_ANNOTATION_VALUE,v,"double"),
+                                                                                       getSourceLocation());
+                                                                       scope.getWorld().getMessageHandler().handleMessage(m);  
+                                                          }
+                                               } else if (t.getSignature()=="B") {
+                                                          try {
+                                                                  Byte value = Byte.parseByte(v);
+                                                                  annotationValues.put(k,value.toString());
+                                                          } catch (NumberFormatException nfe) {
+                                                                  IMessage m = MessageUtil.error(
+                                                                                       WeaverMessages.format(WeaverMessages.INVALID_ANNOTATION_VALUE,v,"byte"),
+                                                                                       getSourceLocation());
+                                                                       scope.getWorld().getMessageHandler().handleMessage(m);  
+                                                          }
+                                               } else if (t.getSignature()=="C") {
+                                                       if (v.length()!=3) {  // '?'
+                                                                 IMessage m = MessageUtil.error(
+                                                                                       WeaverMessages.format(WeaverMessages.INVALID_ANNOTATION_VALUE,v,"char"),
+                                                                                       getSourceLocation());
+                                                                       scope.getWorld().getMessageHandler().handleMessage(m);  
+                                                       } else {
+                                                               annotationValues.put(k,v.substring(1,2));
+                                                       }
+                                               } else {
+                                                       throw new RuntimeException("Not implemented for "+t);
+                                               }
+                                       } else if (t.equals(ResolvedType.JAVA_LANG_STRING)) {
+                                               // nothing to do, it will be OK
+                                       } else {
+                                               throw new RuntimeException("Compiler limitation: annotation value support not implemented for type "+t);
+                                       }
+                               }
+                       }
+                       if (!validKey) {
+                               IMessage m = MessageUtil.error(
+                                               WeaverMessages.format(WeaverMessages.UNKNOWN_ANNOTATION_VALUE,annotationType,k),
+                                               getSourceLocation());
+                               scope.getWorld().getMessageHandler().handleMessage(m);  
+                       }
+               }
+       }
+
+
+
+
        public FuzzyBoolean matches(AnnotatedElement annotated,ResolvedType[] parameterAnnotations) {
                if (!resolved) {
                        throw new IllegalStateException("Can't match on an unresolved annotation type pattern");
                }
+               if (annotationValues!=null) {
+                       // PVAL improve this restriction, would allow '*(value=Color.RED)'
+                       throw new IllegalStateException("Cannot use annotationvalues with a wild annotation pattern");
+               }
                if (isForParameterAnnotationMatch()) {
                        if (parameterAnnotations!=null && parameterAnnotations.length!=0) {
                                for (int i = 0; i < parameterAnnotations.length; i++) {
@@ -114,7 +269,9 @@ public class WildAnnotationTypePattern extends AnnotationTypePattern {
                                scope.getWorld().getMessageHandler().handleMessage(m);
                                resolved = false;
                        }
-               ExactAnnotationTypePattern eatp =  new ExactAnnotationTypePattern(et.getExactType().resolve(scope.getWorld()));
+                       ResolvedType annotationType = et.getExactType().resolve(scope.getWorld());
+               resolveAnnotationValues(annotationType,scope);
+               ExactAnnotationTypePattern eatp = new ExactAnnotationTypePattern(annotationType,annotationValues);
                eatp.copyLocationFrom(this);
            if (isForParameterAnnotationMatch()) eatp.setForParameterAnnotationMatch();
                return eatp;
@@ -140,10 +297,22 @@ public class WildAnnotationTypePattern extends AnnotationTypePattern {
                typePattern.write(s);
                writeLocation(s);
                s.writeBoolean(isForParameterAnnotationMatch());
+               // PVAL
+               if (annotationValues==null) {
+                       s.writeInt(0);
+               } else {
+                       s.writeInt(annotationValues.size());
+                       Set key = annotationValues.keySet();
+                       for (Iterator keys = key.iterator(); keys.hasNext();) {
+                               String k = (String) keys.next();
+                               s.writeUTF(k);
+                               s.writeUTF((String)annotationValues.get(k));
+                       }
+               }
        }
 
        public static AnnotationTypePattern read(VersionedDataInputStream s,ISourceContext context) throws IOException {
-               AnnotationTypePattern ret;
+               WildAnnotationTypePattern ret;
                byte version = s.readByte();
                if (version > VERSION) {
                        throw new BCException("ExactAnnotationTypePattern was written by a newer version of AspectJ");
@@ -154,6 +323,18 @@ public class WildAnnotationTypePattern extends AnnotationTypePattern {
                if (s.getMajorVersion()>=WeaverVersionInfo.WEAVER_VERSION_MINOR_AJ160) {
                        if (s.readBoolean()) ret.setForParameterAnnotationMatch();
                }
+               if (s.getMajorVersion()>=WeaverVersionInfo.WEAVER_VERSION_MAJOR_AJ160M2) {
+                       int annotationValueCount = s.readInt();
+                       if (annotationValueCount>0) {
+                               Map aValues = new HashMap();
+                               for (int i=0;i<annotationValueCount;i++) {
+                                       String key = s.readUTF();
+                                       String val = s.readUTF();
+                                       aValues.put(key,val);
+                               }
+                               ret.annotationValues = aValues;
+                       }
+               }
                return ret;             
        }