package org.aspectj.weaver.patterns;
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.AjAttribute.WeaverVersionInfo;
import org.aspectj.weaver.AnnotatedElement;
import org.aspectj.weaver.BCException;
import org.aspectj.weaver.CompressingDataOutputStream;
import org.aspectj.weaver.ISourceContext;
import org.aspectj.weaver.ResolvedMember;
import org.aspectj.weaver.ResolvedType;
import org.aspectj.weaver.UnresolvedType;
import org.aspectj.weaver.VersionedDataInputStream;
import org.aspectj.weaver.WeaverMessages;
import org.aspectj.weaver.World;
public class WildAnnotationTypePattern extends AnnotationTypePattern {
private TypePattern typePattern;
private boolean resolved = false;
Map<String, String> annotationValues;
public WildAnnotationTypePattern(TypePattern typePattern) {
super();
this.typePattern = typePattern;
this.setLocation(typePattern.getSourceContext(), typePattern.start, typePattern.end);
}
public WildAnnotationTypePattern(TypePattern typePattern, Map<String, String> annotationValues) {
super();
this.typePattern = typePattern;
this.annotationValues = annotationValues;
this.setLocation(typePattern.getSourceContext(), typePattern.start, typePattern.end);
}
public TypePattern getTypePattern() {
return typePattern;
}
@Override
public FuzzyBoolean matches(AnnotatedElement annotated) {
return matches(annotated, null);
}
protected void resolveAnnotationValues(ResolvedType annotationType, IScope scope) {
if (annotationValues == null) {
return;
}
Map<String,String> replacementValues = new HashMap<String,String>();
Set<String> keys = annotationValues.keySet();
ResolvedMember[] ms = annotationType.getDeclaredMethods();
for (String k: keys) {
String key = k;
if (k.endsWith("!")) {
key = key.substring(0, k.length() - 1);
}
String v = annotationValues.get(k);
boolean validKey = false;
for (int i = 0; i < ms.length; i++) {
ResolvedMember resolvedMember = ms[i];
if (resolvedMember.getName().equals(key) && resolvedMember.isAbstract()) {
validKey = true;
ResolvedType t = resolvedMember.getReturnType().resolve(scope.getWorld());
if (t.isEnum()) {
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);
replacementValues.put(k, v);
break;
}
} else if (t.isPrimitiveType()) {
if (t.getSignature().equals("I")) {
try {
int value = Integer.parseInt(v);
replacementValues.put(k, Integer.toString(value));
break;
} 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().equals("F")) {
try {
float value = Float.parseFloat(v);
replacementValues.put(k, Float.toString(value));
break;
} 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().equals("Z")) {
if (v.equalsIgnoreCase("true") || v.equalsIgnoreCase("false")) {
} else {
IMessage m = MessageUtil.error(
WeaverMessages.format(WeaverMessages.INVALID_ANNOTATION_VALUE, v, "boolean"),
getSourceLocation());
scope.getWorld().getMessageHandler().handleMessage(m);
}
} else if (t.getSignature().equals("S")) {
try {
short value = Short.parseShort(v);
replacementValues.put(k, Short.toString(value));
break;
} 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().equals("J")) {
try {
replacementValues.put(k, Long.toString(Long.parseLong(v)));
break;
} 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().equals("D")) {
try {
replacementValues.put(k, Double.toString(Double.parseDouble(v)));
break;
} 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().equals("B")) {
try {
replacementValues.put(k, Byte.toString(Byte.parseByte(v)));
break;
} 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().equals("C")) {
if (v.length() != 3) {
IMessage m = MessageUtil.error(
WeaverMessages.format(WeaverMessages.INVALID_ANNOTATION_VALUE, v, "char"),
getSourceLocation());
scope.getWorld().getMessageHandler().handleMessage(m);
} else {
replacementValues.put(k, v.substring(1, 2));
break;
}
} else {
throw new RuntimeException("Not implemented for " + t);
}
} else if (t.equals(ResolvedType.JL_STRING)) {
} else if (t.equals(ResolvedType.JL_CLASS) || (t.isParameterizedOrGenericType() && t.getRawType().equals(ResolvedType.JL_CLASS))) {
String typename = v.substring(0, v.lastIndexOf('.'));
ResolvedType rt = scope.lookupType(typename, this).resolve(scope.getWorld());
if (rt.isMissing()) {
IMessage m = MessageUtil.error("Unable to resolve type '" + v + "' specified for value '" + k + "'",
getSourceLocation());
scope.getWorld().getMessageHandler().handleMessage(m);
}
replacementValues.put(k, rt.getSignature());
break;
} else {
if (t.isAnnotation()) {
if (v.indexOf("(") != -1) {
throw new RuntimeException(
"Compiler limitation: annotation values can only currently be marker annotations (no values): "
+ v);
}
String typename = v.substring(1);
ResolvedType rt = scope.lookupType(typename, this).resolve(scope.getWorld());
if (rt.isMissing()) {
IMessage m = MessageUtil.error(
"Unable to resolve type '" + v + "' specified for value '" + k + "'", getSourceLocation());
scope.getWorld().getMessageHandler().handleMessage(m);
}
replacementValues.put(k, rt.getSignature());
break;
} else {
scope.message(MessageUtil.error(WeaverMessages.format(WeaverMessages.UNSUPPORTED_ANNOTATION_VALUE_TYPE,t), getSourceLocation()));
replacementValues.put(k,"");
}
}
}
}
if (!validKey) {
IMessage m = MessageUtil.error(WeaverMessages.format(WeaverMessages.UNKNOWN_ANNOTATION_VALUE, annotationType, k),
getSourceLocation());
scope.getWorld().getMessageHandler().handleMessage(m);
}
}
annotationValues.putAll(replacementValues);
}
@Override
public FuzzyBoolean matches(AnnotatedElement annotated, ResolvedType[] parameterAnnotations) {
if (!resolved) {
throw new IllegalStateException("Can't match on an unresolved annotation type pattern");
}
if (annotationValues != null && !typePattern.hasFailedResolution()) {
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++) {
if (typePattern.matches(parameterAnnotations[i], TypePattern.STATIC).alwaysTrue()) {
return FuzzyBoolean.YES;
}
}
}
} else {
ResolvedType[] annTypes = annotated.getAnnotationTypes();
if (annTypes != null && annTypes.length != 0) {
for (int i = 0; i < annTypes.length; i++) {
if (typePattern.matches(annTypes[i], TypePattern.STATIC).alwaysTrue()) {
return FuzzyBoolean.YES;
}
}
}
}
return FuzzyBoolean.NO;
}
@Override
public void resolve(World world) {
if (!resolved) {
if (typePattern instanceof WildTypePattern && (annotationValues == null || annotationValues.isEmpty())) {
WildTypePattern wildTypePattern = (WildTypePattern) typePattern;
String fullyQualifiedName = wildTypePattern.maybeGetCleanName();
if (fullyQualifiedName != null && fullyQualifiedName.indexOf(".") != -1) {
ResolvedType resolvedType = world.resolve(UnresolvedType.forName(fullyQualifiedName));
if (resolvedType != null && !resolvedType.isMissing()) {
typePattern = new ExactTypePattern(resolvedType, false, false);
}
}
}
resolved = true;
}
}
@Override
public AnnotationTypePattern resolveBindings(IScope scope, Bindings bindings, boolean allowBinding) {
if (!scope.getWorld().isInJava5Mode()) {
scope.message(MessageUtil.error(WeaverMessages.format(WeaverMessages.ANNOTATIONS_NEED_JAVA5), getSourceLocation()));
return this;
}
if (resolved) {
return this;
}
this.typePattern = typePattern.resolveBindings(scope, bindings, false, false);
resolved = true;
if (typePattern instanceof ExactTypePattern) {
ExactTypePattern et = (ExactTypePattern) typePattern;
if (!et.getExactType().resolve(scope.getWorld()).isAnnotation()) {
IMessage m = MessageUtil.error(
WeaverMessages.format(WeaverMessages.REFERENCE_TO_NON_ANNOTATION_TYPE, et.getExactType().getName()),
getSourceLocation());
scope.getWorld().getMessageHandler().handleMessage(m);
resolved = false;
}
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;
} else {
return this;
}
}
@Override
public AnnotationTypePattern parameterizeWith(Map<String,UnresolvedType> typeVariableMap, World w) {
WildAnnotationTypePattern ret = new WildAnnotationTypePattern(typePattern.parameterizeWith(typeVariableMap, w));
ret.copyLocationFrom(this);
ret.resolved = resolved;
return ret;
}
private static final byte VERSION = 1;
@Override
public void write(CompressingDataOutputStream s) throws IOException {
s.writeByte(AnnotationTypePattern.WILD);
s.writeByte(VERSION);
typePattern.write(s);
writeLocation(s);
s.writeBoolean(isForParameterAnnotationMatch());
if (annotationValues == null) {
s.writeInt(0);
} else {
s.writeInt(annotationValues.size());
Set<String> key = annotationValues.keySet();
for (Iterator<String> keys = key.iterator(); keys.hasNext();) {
String k = keys.next();
s.writeUTF(k);
s.writeUTF(annotationValues.get(k));
}
}
}
public static AnnotationTypePattern read(VersionedDataInputStream s, ISourceContext context) throws IOException {
WildAnnotationTypePattern ret;
byte version = s.readByte();
if (version > VERSION) {
throw new BCException("ExactAnnotationTypePattern was written by a newer version of AspectJ");
}
TypePattern t = TypePattern.read(s, context);
ret = new WildAnnotationTypePattern(t);
ret.readLocation(context, s);
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<String, String> aValues = new HashMap<String, String>();
for (int i = 0; i < annotationValueCount; i++) {
String key = s.readUTF();
String val = s.readUTF();
aValues.put(key, val);
}
ret.annotationValues = aValues;
}
}
return ret;
}
@Override
public boolean equals(Object obj) {
if (!(obj instanceof WildAnnotationTypePattern)) {
return false;
}
WildAnnotationTypePattern other = (WildAnnotationTypePattern) obj;
return other.typePattern.equals(typePattern)
&& this.isForParameterAnnotationMatch() == other.isForParameterAnnotationMatch()
&& (annotationValues == null ? other.annotationValues == null : annotationValues.equals(other.annotationValues));
}
@Override
public int hashCode() {
return (((17 + 37 * typePattern.hashCode()) * 37 + (isForParameterAnnotationMatch() ? 0 : 1)) * 37)
+ (annotationValues == null ? 0 : annotationValues.hashCode());
}
@Override
public String toString() {
return "@(" + typePattern.toString() + ")";
}
@Override
public Object accept(PatternNodeVisitor visitor, Object data) {
return visitor.visit(this, data);
}
}