summaryrefslogtreecommitdiffstats
path: root/weaver
diff options
context:
space:
mode:
Diffstat (limited to 'weaver')
-rw-r--r--weaver/src/org/aspectj/weaver/bcel/BcelShadow.java64
-rw-r--r--weaver/src/org/aspectj/weaver/bcel/ParamAnnotationAccessVar.java206
2 files changed, 267 insertions, 3 deletions
diff --git a/weaver/src/org/aspectj/weaver/bcel/BcelShadow.java b/weaver/src/org/aspectj/weaver/bcel/BcelShadow.java
index 10fdbd05c..914e99697 100644
--- a/weaver/src/org/aspectj/weaver/bcel/BcelShadow.java
+++ b/weaver/src/org/aspectj/weaver/bcel/BcelShadow.java
@@ -875,6 +875,7 @@ public class BcelShadow extends Shadow {
private BcelVar targetVar = null;
private BcelVar[] argVars = null;
private Map<ResolvedType, AnnotationAccessVar> kindedAnnotationVars = null;
+ private Map<ResolvedType,AnnotationAccessVar>[] paramAnnoVars = null;
private Map<ResolvedType, TypeAnnotationAccessVar> thisAnnotationVars = null;
private Map<ResolvedType, TypeAnnotationAccessVar> targetAnnotationVars = null;
// private Map/* <UnresolvedType,BcelVar> */[] argAnnotationVars = null;
@@ -953,6 +954,12 @@ public class BcelShadow extends Shadow {
}
@Override
+ public Var getArgParamAnnotationVar(int parameterIndex, UnresolvedType forAnnotationType) {
+ initializeKindedAnnotationVars();
+ return paramAnnoVars[parameterIndex].get(forAnnotationType);
+ }
+
+ @Override
public Var getWithinAnnotationVar(UnresolvedType forAnnotationType) {
initializeWithinAnnotationVars();
return withinAnnotationVars.get(forAnnotationType);
@@ -1538,6 +1545,41 @@ public class BcelShadow extends Shadow {
}
return foundMember.getAnnotationTypes();
}
+
+ protected ResolvedType[][] getParameterAnnotations(ResolvedMember foundMember, Member relevantMember, ResolvedType relevantType) {
+ if (foundMember == null) {
+ // check the ITD'd dooberries
+ List<ConcreteTypeMunger> mungers = relevantType.resolve(world).getInterTypeMungers();
+ for (Iterator<ConcreteTypeMunger> iter = mungers.iterator(); iter.hasNext();) {
+ Object munger = iter.next();
+ ConcreteTypeMunger typeMunger = (ConcreteTypeMunger) munger;
+ if (typeMunger.getMunger() instanceof NewMethodTypeMunger
+ || typeMunger.getMunger() instanceof NewConstructorTypeMunger) {
+ ResolvedMember fakerm = typeMunger.getSignature();
+ // if (fakerm.hasAnnotations())
+
+ ResolvedMember ajcMethod = (getSignature().getKind() == ResolvedMember.CONSTRUCTOR ? AjcMemberMaker
+ .postIntroducedConstructor(typeMunger.getAspectType(), fakerm.getDeclaringType(),
+ fakerm.getParameterTypes()) : AjcMemberMaker.interMethodDispatcher(fakerm,
+ typeMunger.getAspectType()));
+ // AjcMemberMaker.interMethodBody(fakerm,typeMunger.getAspectType()));
+ ResolvedMember rmm = findMethod(typeMunger.getAspectType(), ajcMethod);
+ if (fakerm.getName().equals(getSignature().getName())
+ && fakerm.getParameterSignature().equals(getSignature().getParameterSignature())) {
+ relevantType = typeMunger.getAspectType();
+ foundMember = rmm;
+ return foundMember.getParameterAnnotationTypes();
+ }
+ }
+ }
+ // didn't find in ITDs, look in supers
+ foundMember = relevantType.lookupMemberWithSupersAndITDs(relevantMember);
+ if (foundMember == null) {
+ throw new IllegalStateException("Couldn't find member " + relevantMember + " for type " + relevantType);
+ }
+ }
+ return foundMember.getParameterAnnotationTypes();
+ }
/**
* By determining what "kind" of shadow we are, we can find out the annotations on the appropriate element (method, field,
@@ -1550,6 +1592,7 @@ public class BcelShadow extends Shadow {
kindedAnnotationVars = new HashMap<ResolvedType, AnnotationAccessVar>();
ResolvedType[] annotations = null;
+ ResolvedType[][] paramAnnotations = null;
Member shadowSignature = getSignature();
Member annotationHolder = getSignature();
ResolvedType relevantType = shadowSignature.getDeclaringType().resolve(world);
@@ -1564,6 +1607,7 @@ public class BcelShadow extends Shadow {
} else if (getKind() == Shadow.MethodCall || getKind() == Shadow.ConstructorCall) {
ResolvedMember foundMember = findMethod2(relevantType.resolve(world).getDeclaredMethods(), getSignature());
annotations = getAnnotations(foundMember, shadowSignature, relevantType);
+ paramAnnotations = getParameterAnnotations(foundMember, shadowSignature, relevantType);
annotationHolder = getRelevantMember(foundMember, shadowSignature, relevantType);
relevantType = annotationHolder.getDeclaringType().resolve(world);
} else if (getKind() == Shadow.FieldSet || getKind() == Shadow.FieldGet) {
@@ -1589,17 +1633,15 @@ public class BcelShadow extends Shadow {
} else if (getKind() == Shadow.MethodExecution || getKind() == Shadow.ConstructorExecution
|| getKind() == Shadow.AdviceExecution) {
-
ResolvedMember foundMember = findMethod2(relevantType.getDeclaredMethods(), getSignature());
annotations = getAnnotations(foundMember, shadowSignature, relevantType);
+ paramAnnotations = getParameterAnnotations(foundMember, shadowSignature, relevantType);
annotationHolder = getRelevantMember(foundMember, annotationHolder, relevantType);
UnresolvedType ut = annotationHolder.getDeclaringType();
relevantType = ut.resolve(world);
-
} else if (getKind() == Shadow.ExceptionHandler) {
relevantType = getSignature().getParameterTypes()[0].resolve(world);
annotations = relevantType.getAnnotationTypes();
-
} else if (getKind() == Shadow.PreInitialization || getKind() == Shadow.Initialization) {
ResolvedMember found = findMethod2(relevantType.getDeclaredMethods(), getSignature());
annotations = found.getAnnotationTypes();
@@ -1615,6 +1657,22 @@ public class BcelShadow extends Shadow {
annotationHolder, false);
kindedAnnotationVars.put(annotationType, accessVar);
}
+
+ if (paramAnnotations != null) {
+ int max = paramAnnotations.length;
+ paramAnnoVars = new HashMap[max];
+ for (int p=0;p<max;p++) {
+ ResolvedType[] annotationsOnParticularParam = paramAnnotations[p];
+ paramAnnoVars[p] = new HashMap<ResolvedType,AnnotationAccessVar>();
+ for (int i=0;i<annotationsOnParticularParam.length;i++) {
+// for (ResolvedType annotationOnParticularParam: annotationsOnParticularParam) {
+ ResolvedType annotationOnParticularParam = annotationsOnParticularParam[i];
+ ParamAnnotationAccessVar paramAccessVar = new ParamAnnotationAccessVar(this, getKind(), annotationOnParticularParam, relevantType,
+ annotationHolder, false, p, i);
+ paramAnnoVars[p].put(annotationOnParticularParam, paramAccessVar);
+ }
+ }
+ }
}
private ResolvedMember findMethod2(ResolvedMember members[], Member sig) {
diff --git a/weaver/src/org/aspectj/weaver/bcel/ParamAnnotationAccessVar.java b/weaver/src/org/aspectj/weaver/bcel/ParamAnnotationAccessVar.java
new file mode 100644
index 000000000..e3cebc37f
--- /dev/null
+++ b/weaver/src/org/aspectj/weaver/bcel/ParamAnnotationAccessVar.java
@@ -0,0 +1,206 @@
+/* *******************************************************************
+ * Copyright (c) 2016 Contributors
+ * 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
+ *
+ * Contributors:
+ * Andy Clement initial implementation
+ * ******************************************************************/
+package org.aspectj.weaver.bcel;
+
+import org.aspectj.apache.bcel.Constants;
+import org.aspectj.apache.bcel.classfile.Field;
+import org.aspectj.apache.bcel.generic.Instruction;
+import org.aspectj.apache.bcel.generic.InstructionBranch;
+import org.aspectj.apache.bcel.generic.InstructionConstants;
+import org.aspectj.apache.bcel.generic.InstructionFactory;
+import org.aspectj.apache.bcel.generic.InstructionHandle;
+import org.aspectj.apache.bcel.generic.InstructionList;
+import org.aspectj.apache.bcel.generic.ObjectType;
+import org.aspectj.apache.bcel.generic.Type;
+import org.aspectj.weaver.Member;
+import org.aspectj.weaver.ResolvedType;
+import org.aspectj.weaver.Shadow;
+import org.aspectj.weaver.Shadow.Kind;
+import org.aspectj.weaver.UnresolvedType;
+import org.aspectj.weaver.ast.Var;
+
+/**
+ * Represents access to an parameter annotation on a member element.
+ */
+public class ParamAnnotationAccessVar extends AnnotationAccessVar {
+
+ private BcelShadow shadow;
+ private Kind kind; // What kind of shadow are we at?
+ private UnresolvedType containingType; // The type upon which we want to ask for 'member'
+ private Member member; // Holds the member that has the annotations (for method/field join points)
+ private boolean isWithin; // implies @within() or @withincode(). If false, that implies @annotation()
+ private int parameterNumber;
+ private int annotationOnParameterNumber;
+
+ public ParamAnnotationAccessVar(BcelShadow shadow, Kind kind, ResolvedType annotationType,
+ UnresolvedType theTargetIsStoredHere, Member sig, boolean isWithin, int parameterNumber, int annotationOnParameterNumber) {
+ super(shadow, kind, annotationType, theTargetIsStoredHere, sig, isWithin);
+ this.shadow = shadow;
+ this.kind = kind;
+ this.containingType = theTargetIsStoredHere;
+ this.member = sig;
+ this.isWithin = isWithin;
+ this.parameterNumber = parameterNumber;
+ this.annotationOnParameterNumber = annotationOnParameterNumber;
+ }
+
+ @Override
+ public String toString() {
+ return "ParamAnnotationAccessVar(" + getType() + ")";
+ }
+
+ private InstructionList createLoadInstructions(ResolvedType toType, InstructionFactory fact) {
+ InstructionList il = new InstructionList();
+ Type jlClass = BcelWorld.makeBcelType(UnresolvedType.JL_CLASS);
+ Type jlString = BcelWorld.makeBcelType(UnresolvedType.JL_STRING);
+ Type jlClassArray = BcelWorld.makeBcelType(UnresolvedType.JAVA_LANG_CLASS_ARRAY);
+ Type jlaAnnotation = BcelWorld.makeBcelType(UnresolvedType.JAVA_LANG_ANNOTATION);
+ Type jlaAnnotationArrayArray = BcelWorld.makeBcelType(UnresolvedType.makeArray(UnresolvedType.JAVA_LANG_ANNOTATION, 2));
+ Instruction pushConstant = fact.createConstant(new ObjectType(toType.getName()));
+ if (kind == Shadow.MethodCall || kind == Shadow.MethodExecution || kind == Shadow.PreInitialization
+ || kind == Shadow.Initialization || kind == Shadow.ConstructorCall || kind == Shadow.ConstructorExecution
+ || kind == Shadow.AdviceExecution ||
+ // annotations for fieldset/fieldget when an ITD is involved are stored against a METHOD
+ ((kind == Shadow.FieldGet || kind == Shadow.FieldSet) && member.getKind() == Member.METHOD)) {
+
+ Type jlrMethod = BcelWorld.makeBcelType(UnresolvedType.forSignature("Ljava/lang/reflect/Method;"));
+ Type jlAnnotation = BcelWorld.makeBcelType(UnresolvedType.forSignature("Ljava/lang/annotation/Annotation;"));
+ Type[] paramTypes = BcelWorld.makeBcelTypes(member.getParameterTypes());
+
+ if (kind == Shadow.MethodCall
+ || kind == Shadow.MethodExecution
+ || kind == Shadow.AdviceExecution
+ ||
+ // annotations for fieldset/fieldget when an ITD is involved are stored against a METHOD
+ ((kind == Shadow.FieldGet || kind == Shadow.FieldSet) && member.getKind() == Member.METHOD)
+ || ((kind == Shadow.ConstructorCall || kind == Shadow.ConstructorExecution) && member.getKind() == Member.METHOD)) {
+
+ // Need to look at the cached annotation before going to fetch it again
+ Field annotationCachingField = shadow.getEnclosingClass().getAnnotationCachingField(shadow, toType, isWithin);
+
+ // Basic idea here is to check if the cached field is null, if it is then initialize it, otherwise use it
+ il.append(fact.createGetStatic(shadow.getEnclosingClass().getName(), annotationCachingField.getName(), jlAnnotation));
+ il.append(InstructionConstants.DUP);
+ InstructionBranch ifNonNull = InstructionFactory.createBranchInstruction(Constants.IFNONNULL, null);
+ il.append(ifNonNull);
+ il.append(InstructionConstants.POP);
+ il.append(fact.createConstant(BcelWorld.makeBcelType(containingType)));
+
+ il.append(fact.createConstant(member.getName()));
+ buildArray(il, fact, jlClass, paramTypes, 1);
+ // OPTIMIZE cache result of getDeclaredMethod?
+ il.append(fact.createInvoke("java/lang/Class", "getDeclaredMethod", jlrMethod,
+ new Type[] { jlString, jlClassArray }, Constants.INVOKEVIRTUAL));
+// il.append(pushConstant);// fact.createConstant(new ObjectType(toType.getName())));
+ il.append(fact.createInvoke("java/lang/reflect/Method", "getParameterAnnotations", jlaAnnotationArrayArray, null, Constants.INVOKEVIRTUAL));
+ il.append(fact.createConstant(parameterNumber));
+ il.append(InstructionConstants.AALOAD);
+ il.append(fact.createConstant(annotationOnParameterNumber));
+ il.append(InstructionConstants.AALOAD);
+ il.append(InstructionConstants.DUP);
+ // Could loop over the set of annotations or we could 'guess' the right one?
+
+ il.append(fact.createPutStatic(shadow.getEnclosingClass().getName(), annotationCachingField.getName(), jlAnnotation));
+ InstructionHandle ifNullElse = il.append(InstructionConstants.NOP);
+ ifNonNull.setTarget(ifNullElse);
+
+ } else { // init/preinit/ctor-call/ctor-exec
+ il.append(fact.createConstant(BcelWorld.makeBcelType(containingType)));
+ buildArray(il, fact, jlClass, paramTypes, 1);
+ Type jlrCtor = BcelWorld.makeBcelType(UnresolvedType.JAVA_LANG_REFLECT_CONSTRUCTOR);
+ // OPTIMIZE cache result of getDeclaredConstructor and getAnnotation? Might be able to use it again if someone else
+ // needs the same annotations?
+ il.append(fact.createInvoke("java/lang/Class", "getDeclaredConstructor", jlrCtor, new Type[] { jlClassArray },
+ Constants.INVOKEVIRTUAL));
+ il.append(pushConstant);
+ il.append(fact.createInvoke("java/lang/reflect/Constructor", "getAnnotation", jlaAnnotation,
+ new Type[] { jlClass }, Constants.INVOKEVIRTUAL));
+ }
+ } else {
+ throw new RuntimeException("Don't understand this kind " + kind);
+ }
+ il.append(Utility.createConversion(fact, jlaAnnotation, BcelWorld.makeBcelType(toType)));
+ return il;
+ }
+
+ private void buildArray(InstructionList il, InstructionFactory fact, Type arrayElementType, Type[] arrayEntries, int dim) {
+ il.append(fact.createConstant(Integer.valueOf(arrayEntries == null ? 0 : arrayEntries.length)));
+ il.append(fact.createNewArray(arrayElementType, (short) dim));
+ if (arrayEntries == null) {
+ return;
+ }
+ for (int i = 0; i < arrayEntries.length; i++) {
+ il.append(InstructionFactory.createDup(1));
+ il.append(fact.createConstant(Integer.valueOf(i)));
+ switch (arrayEntries[i].getType()) {
+ case Constants.T_ARRAY:
+ il.append(fact.createConstant(new ObjectType(arrayEntries[i].getSignature()))); // FIXME should be getName() and not
+ // getSignature()?
+ break;
+ case Constants.T_BOOLEAN:
+ il.append(fact.createGetStatic("java/lang/Boolean", "TYPE", arrayElementType));
+ break;
+ case Constants.T_BYTE:
+ il.append(fact.createGetStatic("java/lang/Byte", "TYPE", arrayElementType));
+ break;
+ case Constants.T_CHAR:
+ il.append(fact.createGetStatic("java/lang/Character", "TYPE", arrayElementType));
+ break;
+ case Constants.T_INT:
+ il.append(fact.createGetStatic("java/lang/Integer", "TYPE", arrayElementType));
+ break;
+ case Constants.T_LONG:
+ il.append(fact.createGetStatic("java/lang/Long", "TYPE", arrayElementType));
+ break;
+ case Constants.T_DOUBLE:
+ il.append(fact.createGetStatic("java/lang/Double", "TYPE", arrayElementType));
+ break;
+ case Constants.T_FLOAT:
+ il.append(fact.createGetStatic("java/lang/Float", "TYPE", arrayElementType));
+ break;
+ case Constants.T_SHORT:
+ il.append(fact.createGetStatic("java/lang/Short", "TYPE", arrayElementType));
+ break;
+ default:
+ il.append(fact.createConstant(arrayEntries[i]));
+ }
+ il.append(InstructionConstants.AASTORE);
+ }
+ }
+
+ @Override
+ public void appendLoad(InstructionList il, InstructionFactory fact) {
+ il.append(createLoadInstructions(getType(), fact));
+ }
+
+ @Override
+ public void appendLoadAndConvert(InstructionList il, InstructionFactory fact, ResolvedType toType) {
+ il.append(createLoadInstructions(toType, fact));
+ }
+
+ @Override
+ public void insertLoad(InstructionList il, InstructionFactory fact) {
+ il.insert(createLoadInstructions(getType(), fact));
+ }
+
+ /**
+ * Return an object that can access a particular field of this annotation.
+ *
+ * @param valueType The type from the annotation that is of interest
+ * @param the formal name expressed in the pointcut, can be used to disambiguate
+ * @return a variable that represents access to that annotation field
+ */
+ @Override
+ public Var getAccessorForValue(ResolvedType valueType, String formalName) {
+ throw new IllegalStateException("Not supported for parameter annotations");
+ }
+}