BindingAnnotationFieldTypePattern.java
/* *******************************************************************
* Copyright (c) 2008 Contributors
* All rights reserved.
* This program and the accompanying materials are made available
* under the terms of the Eclipse Public License v 2.0
* which accompanies this distribution and is available at
* https://www.eclipse.org/org/documents/epl-2.0/EPL-2.0.txt
*
* Contributors:
* Andy Clement initial implementation
* ******************************************************************/
package org.aspectj.weaver.patterns;
import java.io.IOException;
import java.util.Map;
import org.aspectj.bridge.IMessage;
import org.aspectj.bridge.MessageUtil;
import org.aspectj.util.FuzzyBoolean;
import org.aspectj.weaver.AnnotatedElement;
import org.aspectj.weaver.BCException;
import org.aspectj.weaver.CompressingDataOutputStream;
import org.aspectj.weaver.ISourceContext;
import org.aspectj.weaver.IntMap;
import org.aspectj.weaver.ReferenceType;
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;
/**
* Represents an attempt to bind the field of an annotation within a pointcut. For example:
* <pre><code>
* before(Level lev): execution(* *(..)) && @annotation(TraceAnnotation(lev))
* </code></pre>
* <p>This binding annotation type pattern will be for 'lev'.</p>
*/
public class BindingAnnotationFieldTypePattern extends ExactAnnotationTypePattern implements BindingPattern {
protected int formalIndex;
UnresolvedType formalType; // In this construct the formal type differs from the annotation type
public BindingAnnotationFieldTypePattern(UnresolvedType formalType, int formalIndex, UnresolvedType theAnnotationType) {
super(theAnnotationType, null);
this.formalIndex = formalIndex;
this.formalType = formalType;
}
public void resolveBinding(World world) {
if (resolved) {
return;
}
resolved = true;
formalType = world.resolve(formalType);
annotationType = world.resolve(annotationType);
ResolvedType annoType = (ResolvedType) annotationType;
if (!annoType.isAnnotation()) {
IMessage m = MessageUtil
.error(WeaverMessages.format(WeaverMessages.REFERENCE_TO_NON_ANNOTATION_TYPE, annoType.getName()),
getSourceLocation());
world.getMessageHandler().handleMessage(m);
resolved = false;
}
}
@Override
public AnnotationTypePattern parameterizeWith(Map typeVariableMap, World w) {
throw new BCException("Parameterization not implemented for annotation field binding construct (compiler limitation)");
// UnresolvedType newAnnotationType = annotationType;
// if (annotationType.isTypeVariableReference()) {
// TypeVariableReference t = (TypeVariableReference) annotationType;
// String key = t.getTypeVariable().getName();
// if (typeVariableMap.containsKey(key)) {
// newAnnotationType = (UnresolvedType) typeVariableMap.get(key);
// }
// } else if (annotationType.isParameterizedType()) {
// newAnnotationType = annotationType.parameterize(typeVariableMap);
// }
// BindingAnnotationTypePattern ret = new BindingAnnotationTypePattern(newAnnotationType, this.formalIndex);
// if (newAnnotationType instanceof ResolvedType) {
// ResolvedType rat = (ResolvedType) newAnnotationType;
// verifyRuntimeRetention(rat.getWorld(), rat);
// }
// ret.copyLocationFrom(this);
// return ret;
}
@Override
public int getFormalIndex() {
return formalIndex;
}
@Override
public boolean equals(Object obj) {
if (!(obj instanceof BindingAnnotationFieldTypePattern)) {
return false;
}
BindingAnnotationFieldTypePattern btp = (BindingAnnotationFieldTypePattern) obj;
return (btp.formalIndex == formalIndex) && (annotationType.equals(btp.annotationType))
&& (formalType.equals(btp.formalType));
}
@Override
public int hashCode() {
return (annotationType.hashCode() * 37 + formalIndex * 37) + formalType.hashCode();
}
@Override
public AnnotationTypePattern remapAdviceFormals(IntMap bindings) {
if (!bindings.hasKey(formalIndex)) {
throw new BCException("Annotation field binding reference must be bound (compiler limitation)");
// must be something like returning the unbound form: return new ExactAnnotationTypePattern(annotationType,
// null);
} else {
int newFormalIndex = bindings.get(formalIndex);
BindingAnnotationFieldTypePattern baftp = new BindingAnnotationFieldTypePattern(formalType, newFormalIndex,
annotationType);
baftp.formalName = formalName;
return baftp;
}
}
@Override
public void write(CompressingDataOutputStream s) throws IOException {
s.writeByte(AnnotationTypePattern.BINDINGFIELD2);
formalType.write(s); // the type of the field within the annotation
s.writeShort((short) formalIndex);
annotationType.write(s); // the annotation type
s.writeUTF(formalName);
writeLocation(s);
}
public static AnnotationTypePattern read(VersionedDataInputStream s, ISourceContext context) throws IOException {
AnnotationTypePattern ret = new BindingAnnotationFieldTypePattern(UnresolvedType.read(s), s.readShort(),
UnresolvedType.read(s));
ret.readLocation(context, s);
return ret;
}
public static AnnotationTypePattern read2(VersionedDataInputStream s, ISourceContext context) throws IOException {
BindingAnnotationFieldTypePattern ret = new BindingAnnotationFieldTypePattern(UnresolvedType.read(s), s.readShort(),
UnresolvedType.read(s));
ret.formalName = s.readUTF();
ret.readLocation(context, s);
return ret;
}
@Override
public FuzzyBoolean matches(AnnotatedElement annotated, ResolvedType[] parameterAnnotations) {
// Inheritance irrelevant because @annotation(Anno(x)) only supported at method execution join points (compiler limitation)
// boolean checkSupers = false;
// if (getResolvedAnnotationType().hasAnnotation(UnresolvedType.AT_INHERITED)) {
// if (annotated instanceof ResolvedType) {
// checkSupers = true;
// }
// }
//
if (annotated.hasAnnotation(annotationType)) {
if (annotationType instanceof ReferenceType) {
ReferenceType rt = (ReferenceType) annotationType;
if (rt.getRetentionPolicy() != null && rt.getRetentionPolicy().equals("SOURCE")) {
rt.getWorld()
.getMessageHandler()
.handleMessage(
MessageUtil.warn(WeaverMessages.format(WeaverMessages.NO_MATCH_BECAUSE_SOURCE_RETENTION,
annotationType, annotated), getSourceLocation()));
return FuzzyBoolean.NO;
}
ResolvedMember[] methods = rt.getDeclaredMethods();
boolean found = false;
for (int i = 0; i < methods.length && !found; i++) {
if (methods[i].getReturnType().equals(formalType)) {
found = true;
}
}
return (found ? FuzzyBoolean.YES : FuzzyBoolean.NO);
}
}
// else if (checkSupers) {
// ResolvedType toMatchAgainst = ((ResolvedType) annotated).getSuperclass();
// while (toMatchAgainst != null) {
// if (toMatchAgainst.hasAnnotation(annotationType)) {
// return FuzzyBoolean.YES;
// }
// toMatchAgainst = toMatchAgainst.getSuperclass();
// }
// }
//
return FuzzyBoolean.NO;
}
public UnresolvedType getFormalType() {
return formalType;
}
}