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;
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);
}
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
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();
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;
}
}
public void resolve(World world) {
- if (!resolved) annotationType = annotationType.resolve(world);
+ if (!resolved) {
+ annotationType = annotationType.resolve(world);
+ }
resolved = true;
}
} 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);
}
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");
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;
}
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.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;
private TypePattern typePattern;
private boolean resolved = false;
+ Map annotationValues;
/**
*
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)
*/
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++) {
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;
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");
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;
}