System.out.println("phew");
}
- @AfterReturning(value="call(Foo+.new(..))",returning="f")
+ @AfterReturning(pointcut="call(Foo+.new(..))",returning="f")
public void itsAFoo(Foo f) {
System.out.println("It's a Foo: " + f);
}
]]></programlisting>
- <para>(Note the need for the "value=" prefix in front of the pointcut
+ <para>(Note the use of the "pointcut=" prefix in front of the pointcut
expression in the returning case).</para>
<para>After throwing advice works in a similar fashion, using the
--- /dev/null
+/*******************************************************************************
+ * Copyright (c) 2005 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://eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Alexandre Vasseur initial implementation
+ *******************************************************************************/
+package ataspectj;
+
+import org.aspectj.lang.annotation.Aspect;
+import org.aspectj.lang.annotation.DeclareWarning;
+import org.aspectj.lang.annotation.DeclareError;
+
+/**
+ * @author <a href="mailto:alex AT gnilux DOT com">Alexandre Vasseur</a>
+ */
+public class DeowTest {
+
+ public void hello() {}
+
+ public void hi() {}
+
+ public void target() {
+ hello();
+ hi();
+ }
+
+ @Aspect
+ public static class DeowAspect {
+
+ @DeclareWarning("call(* hello()) && within(ataspectj.DeowTest)")
+ final static String onHello = "call hello";
+
+ @DeclareError("call(* hi()) && within(ataspectj.DeowTest)")
+ final static String onHi = "call hi";
+ }
+}
public void testAroundInlineMunger2() {
runTest("AroundInlineMunger2");
}
+
+ public void testDeow() {
+ runTest("Deow");
+ }
}
\ No newline at end of file
<compile files="ataspectj/AroundInlineMungerTest2.aj,ataspectj/AroundInlineMungerTestAspects2.aj,ataspectj/TestHelper.java" options="-1.5 -Xlint:ignore"/>
<run class="ataspectj.AroundInlineMungerTest2"/>
</ajc-test>
+
+ <ajc-test dir="java5/ataspectj" title="Deow">
+ <compile files="ataspectj/DeowTest.java" options="-1.5">
+ <message kind="warning" line="28" text="call hello"/>
+ <message kind="error" line="29" text="call hi"/>
+ </compile>
+ </ajc-test>
</suite>
\ No newline at end of file
package org.aspectj.weaver;
+import org.aspectj.lang.JoinPoint;
+import org.aspectj.lang.ProceedingJoinPoint;
+
import java.lang.reflect.Modifier;
//import org.aspectj.weaver.ResolvedTypeX.Name;
"<init>",
"()V");
}
+
+ //-- common types we use. Note: Java 5 dependand types are refered to as String
+ public final static TypeX ASPECT_ANNOTATION = TypeX.forName("org.aspectj.lang.annotation.Aspect");
+ public final static TypeX BEFORE_ANNOTATION = TypeX.forName("org.aspectj.lang.annotation.Before");
+ public final static TypeX AROUND_ANNOTATION = TypeX.forName("org.aspectj.lang.annotation.Around");
+ public final static TypeX AFTERRETURNING_ANNOTATION = TypeX.forName("org.aspectj.lang.annotation.AfterReturning");
+ public final static TypeX AFTERTHROWING_ANNOTATION = TypeX.forName("org.aspectj.lang.annotation.AfterThrowing");
+ public final static TypeX AFTER_ANNOTATION = TypeX.forName("org.aspectj.lang.annotation.After");
+ public final static TypeX POINTCUT_ANNOTATION = TypeX.forName("org.aspectj.lang.annotation.Pointcut");
+ public final static TypeX DECLAREERROR_ANNOTATION = TypeX.forName("org.aspectj.lang.annotation.DeclareError");
+ public final static TypeX DECLAREWARNING_ANNOTATION = TypeX.forName("org.aspectj.lang.annotation.DeclareWarning");
+ public final static TypeX DECLAREPRECEDENCE_ANNOTATION = TypeX.forName("org.aspectj.lang.annotation.DeclarePrecedence");
+
+ public final static TypeX TYPEX_JOINPOINT = TypeX.forName(JoinPoint.class.getName().replace('/','.'));
+ public final static TypeX TYPEX_PROCEEDINGJOINPOINT = TypeX.forName(ProceedingJoinPoint.class.getName().replace('/','.'));
+ public final static TypeX TYPEX_STATICJOINPOINT = TypeX.forName(JoinPoint.StaticPart.class.getName().replace('/','.'));
+ public final static TypeX TYPEX_ENCLOSINGSTATICJOINPOINT = TypeX.forName(JoinPoint.EnclosingStaticPart.class.getName().replace('/','.'));
+
}
+++ /dev/null
-/*******************************************************************************
- * Copyright (c) 2005 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://eclipse.org/legal/epl-v10.html
- *
- * Contributors:
- * initial implementation Alexandre Vasseur
- *******************************************************************************/
-package org.aspectj.weaver.ataspectj;
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.Comparator;
-import java.util.Iterator;
-import java.util.List;
-
-import org.aspectj.apache.bcel.classfile.Attribute;
-import org.aspectj.apache.bcel.classfile.Field;
-import org.aspectj.apache.bcel.classfile.JavaClass;
-import org.aspectj.apache.bcel.classfile.LocalVariable;
-import org.aspectj.apache.bcel.classfile.LocalVariableTable;
-import org.aspectj.apache.bcel.classfile.Method;
-import org.aspectj.apache.bcel.classfile.annotation.Annotation;
-import org.aspectj.apache.bcel.classfile.annotation.ElementNameValuePair;
-import org.aspectj.apache.bcel.classfile.annotation.RuntimeAnnotations;
-import org.aspectj.apache.bcel.classfile.annotation.RuntimeVisibleAnnotations;
-import org.aspectj.apache.bcel.generic.Type;
-import org.aspectj.bridge.IMessageHandler;
-import org.aspectj.bridge.Message;
-import org.aspectj.bridge.IMessage;
-import org.aspectj.lang.JoinPoint;
-import org.aspectj.lang.ProceedingJoinPoint;
-import org.aspectj.weaver.Advice;
-import org.aspectj.weaver.AdviceKind;
-import org.aspectj.weaver.AjAttribute;
-import org.aspectj.weaver.AjcMemberMaker;
-import org.aspectj.weaver.ISourceContext;
-import org.aspectj.weaver.NameMangler;
-import org.aspectj.weaver.ResolvedPointcutDefinition;
-import org.aspectj.weaver.ResolvedTypeX;
-import org.aspectj.weaver.TypeX;
-import org.aspectj.weaver.patterns.DeclarePrecedence;
-import org.aspectj.weaver.patterns.FormalBinding;
-import org.aspectj.weaver.patterns.IScope;
-import org.aspectj.weaver.patterns.PatternParser;
-import org.aspectj.weaver.patterns.PerCflow;
-import org.aspectj.weaver.patterns.PerClause;
-import org.aspectj.weaver.patterns.PerObject;
-import org.aspectj.weaver.patterns.PerSingleton;
-import org.aspectj.weaver.patterns.PerTypeWithin;
-import org.aspectj.weaver.patterns.Pointcut;
-import org.aspectj.weaver.patterns.SimpleScope;
-import org.aspectj.weaver.patterns.ParserException;
-import org.aspectj.weaver.patterns.Declare;
-import org.aspectj.weaver.patterns.DeclareErrorOrWarning;
-
-/**
- * Annotation defined aspect reader.
- * <p/>
- * It reads the Java 5 annotations and turns them into AjAttributes
- *
- * @author <a href="mailto:alex AT gnilux DOT com">Alexandre Vasseur</a>
- */
-public class Aj5Attributes {
-
- private final static List EMPTY_LIST = new ArrayList();
- private final static String[] EMPTY_STRINGS = new String[0];
-
- public final static TypeX TYPEX_JOINPOINT = TypeX.forName(JoinPoint.class.getName().replace('/','.'));
- public final static TypeX TYPEX_PROCEEDINGJOINPOINT = TypeX.forName(ProceedingJoinPoint.class.getName().replace('/','.'));
- public final static TypeX TYPEX_STATICJOINPOINT = TypeX.forName(JoinPoint.StaticPart.class.getName().replace('/','.'));
- public final static TypeX TYPEX_ENCLOSINGSTATICJOINPOINT = TypeX.forName(JoinPoint.EnclosingStaticPart.class.getName().replace('/','.'));
-
- /**
- * A struct that allows to add extra arguments without always breaking the API
- *
- * @author <a href="mailto:alex AT gnilux DOT com">Alexandre Vasseur</a>
- */
- private static class AjAttributeStruct {
-
- /**
- * The list of AjAttribute.XXX that we are populating from the @AJ read
- */
- List ajAttributes = new ArrayList();
-
- /**
- * The resolved type (class) for which we are reading @AJ for (be it class, method, field annotations)
- */
- final ResolvedTypeX enclosingType;
-
- final ISourceContext context;
- final IMessageHandler handler;
-
- public AjAttributeStruct(ResolvedTypeX type, ISourceContext sourceContext, IMessageHandler messageHandler) {
- enclosingType = type;
- context = sourceContext;
- handler = messageHandler;
- }
- }
-
- /**
- * A struct when we read @AJ on method
- *
- * @author <a href="mailto:alex AT gnilux DOT com">Alexandre Vasseur</a>
- */
- private static class AjAttributeMethodStruct extends AjAttributeStruct {
-
- /**
- * Argument names as they appear in the SOURCE code, ordered, and lazyly populated
- * Used to do formal binding
- */
- private String[] m_argumentNamesLazy = null;
-
- final Method method;
-
- public AjAttributeMethodStruct(Method method, ResolvedTypeX type, ISourceContext sourceContext, IMessageHandler messageHandler) {
- super(type, sourceContext, messageHandler);
- this.method = method;
- }
-
- public String[] getArgumentNames() {
- if (m_argumentNamesLazy == null) {
- m_argumentNamesLazy = getMethodArgumentNamesAsInSource(method);
- }
- return m_argumentNamesLazy;
- }
- }
-
- /**
- * A struct when we read @AJ on field
- *
- * @author <a href="mailto:alex AT gnilux DOT com">Alexandre Vasseur</a>
- */
- private static class AjAttributeFieldStruct extends AjAttributeStruct {
-
- final Field field;
-
- public AjAttributeFieldStruct(Field field, ResolvedTypeX type, ISourceContext sourceContext, IMessageHandler messageHandler) {
- super(type, sourceContext, messageHandler);
- this.field = field;
- }
- }
-
- /**
- * Annotations are RuntimeVisible only. This allow us to not visit RuntimeInvisible ones.
- *
- * @param attribute
- * @return
- */
- public static boolean acceptAttribute(Attribute attribute) {
- return (attribute instanceof RuntimeVisibleAnnotations);
- }
-
- /**
- * Extract class level annotations and turn them into AjAttributes.
- *
- * @param javaClass
- * @param type
- * @param context
- * @param msgHandler
- * @return list of AjAttributes
- */
- public static List readAj5ClassAttributes(JavaClass javaClass, ResolvedTypeX type, ISourceContext context,IMessageHandler msgHandler, boolean isCodeStyleAspect) {
- AjAttributeStruct struct = new AjAttributeStruct(type, context, msgHandler);
- Attribute[] attributes = javaClass.getAttributes();
- boolean hasAtAspectAnnotation = false;
- boolean hasAtPrecedenceAnnotation = false;
-
- for (int i = 0; i < attributes.length; i++) {
- Attribute attribute = attributes[i];
- if (acceptAttribute(attribute)) {
- RuntimeAnnotations rvs = (RuntimeAnnotations) attribute;
- // we don't need to look for several attribute occurence since it cannot happen as per JSR175
- if (!isCodeStyleAspect) {
- hasAtAspectAnnotation = handleAspectAnnotation(rvs, struct);
- }
- //TODO: below means mix style for @DeclarePrecedence - are we sure we want that ?
- hasAtPrecedenceAnnotation = handlePrecedenceAnnotation(rvs, struct);
- // there can only be one RuntimeVisible bytecode attribute
- break;
- }
- }
-
- // basic semantic check
- //FIXME AV TBD could be skipped and silently ignore - TBD with Andy
- if (hasAtPrecedenceAnnotation && !hasAtAspectAnnotation) {
- msgHandler.handleMessage(
- new Message(
- "Found @DeclarePrecedence on a non @Aspect type '" + type.getName() + "'",
- IMessage.WARNING,
- null,
- type.getSourceLocation()
- )
- );
- // bypass what we have read
- return EMPTY_LIST;
- }
- //FIXME turn on when ajcMightHaveAspect fixed
-// if (hasAtAspectAnnotation && type.isInterface()) {
-// msgHandler.handleMessage(
-// new Message(
-// "Found @Aspect on an interface type '" + type.getName() + "'",
-// IMessage.WARNING,
-// null,
-// type.getSourceLocation()
-// )
-// );
-// // bypass what we have read
-// return EMPTY_LIST;
-// }
-
- // the following block will not detect @Pointcut in non @Aspect types for optimization purpose
- // FIXME AV TBD with Andy
- if (!hasAtAspectAnnotation) {
- return EMPTY_LIST;
- }
-
- // code style pointcuts are class attributes
- // we need to gather the @AJ pointcut right now and not at method level annotation extraction time
- // in order to be able to resolve the pointcut references later on
- //FIXME alex loop over class super class
- //FIXME alex can that be too slow ?
- for (int i = 0; i < javaClass.getMethods().length; i++) {
- Method method = javaClass.getMethods()[i];
- if (method.getName().startsWith(NameMangler.PREFIX)) continue; // already dealt with by ajc...
- //FIXME alex optimize, this method struct will gets recreated for advice extraction
- AjAttributeMethodStruct mstruct = new AjAttributeMethodStruct(method, type, context, msgHandler);
- Attribute[] mattributes = method.getAttributes();
-
- for (int j = 0; j < mattributes.length; j++) {
- Attribute mattribute = mattributes[j];
- if (acceptAttribute(mattribute)) {
- RuntimeAnnotations mrvs = (RuntimeAnnotations) mattribute;
- handlePointcutAnnotation(mrvs, mstruct);
- // there can only be one RuntimeVisible bytecode attribute
- break;
- }
- }
- struct.ajAttributes.addAll(mstruct.ajAttributes);
- }
-
-
- // code style declare error / warning are class attributes
- for (int i = 0; i < javaClass.getFields().length; i++) {
- Field field = javaClass.getFields()[i];
- if (field.getName().startsWith(NameMangler.PREFIX)) continue; // already dealt with by ajc...
- //FIXME alex optimize, this method struct will gets recreated for advice extraction
- AjAttributeFieldStruct fstruct = new AjAttributeFieldStruct(field, type, context, msgHandler);
- Attribute[] fattributes = field.getAttributes();
-
- for (int j = 0; j < fattributes.length; j++) {
- Attribute fattribute = fattributes[j];
- if (acceptAttribute(fattribute)) {
- RuntimeAnnotations frvs = (RuntimeAnnotations) fattribute;
- if (handleDeclareErrorOrWarningAnnotation(frvs, fstruct)) {
- // semantic check - must be in an @Aspect [remove if previous block bypassed in advance]
- if (!type.isAnnotationStyleAspect()) {
- msgHandler.handleMessage(
- new Message(
- "Found @AspectJ annotations in a non @Aspect type '" + type.getName() + "'",
- IMessage.WARNING,
- null,
- type.getSourceLocation()
- )
- );
- ;// go ahead
- }
- }
- // there can only be one RuntimeVisible bytecode attribute
- break;
- }
- }
- struct.ajAttributes.addAll(fstruct.ajAttributes);
- }
- return struct.ajAttributes;
- }
-
- /**
- * Extract method level annotations and turn them into AjAttributes.
- *
- * @param method
- * @param type
- * @param context
- * @param msgHandler
- * @return list of AjAttributes
- */
- public static List readAj5MethodAttributes(Method method, ResolvedTypeX type, ResolvedPointcutDefinition preResolvedPointcut, ISourceContext context,IMessageHandler msgHandler) {
- if (method.getName().startsWith(NameMangler.PREFIX)) return Collections.EMPTY_LIST; // already dealt with by ajc...
-
- AjAttributeMethodStruct struct = new AjAttributeMethodStruct(method, type, context, msgHandler);
- Attribute[] attributes = method.getAttributes();
-
- // we remember if we found one @AJ annotation for minimal semantic error reporting
- // the real reporting beeing done thru AJDT and the compiler mapping @AJ to AjAtttribute
- // or thru APT
- // FIXME AV we could actually skip the whole thing if type is not itself an @Aspect
- // but then we would not see any warning. TBD with Andy
- boolean hasAtAspectJAnnotation = false;
- boolean hasAtAspectJAnnotationMustReturnVoid = false;
- for (int i = 0; i < attributes.length; i++) {
- Attribute attribute = attributes[i];
- if (acceptAttribute(attribute)) {
- RuntimeAnnotations rvs = (RuntimeAnnotations) attribute;
- hasAtAspectJAnnotationMustReturnVoid = hasAtAspectJAnnotationMustReturnVoid || handleBeforeAnnotation(rvs, struct, preResolvedPointcut);
- hasAtAspectJAnnotationMustReturnVoid = hasAtAspectJAnnotationMustReturnVoid || handleAfterAnnotation(rvs, struct, preResolvedPointcut);
- hasAtAspectJAnnotationMustReturnVoid = hasAtAspectJAnnotationMustReturnVoid || handleAfterReturningAnnotation(rvs, struct, preResolvedPointcut);
- hasAtAspectJAnnotationMustReturnVoid = hasAtAspectJAnnotationMustReturnVoid || handleAfterThrowingAnnotation(rvs, struct, preResolvedPointcut);
- hasAtAspectJAnnotation = hasAtAspectJAnnotation || handleAroundAnnotation(rvs, struct, preResolvedPointcut);
- // there can only be one RuntimeVisible bytecode attribute
- break;
- }
- }
- hasAtAspectJAnnotation = hasAtAspectJAnnotation || hasAtAspectJAnnotationMustReturnVoid;
-
- // semantic check - must be in an @Aspect [remove if previous block bypassed in advance]
- if (hasAtAspectJAnnotation && !type.isAnnotationStyleAspect()) {
- msgHandler.handleMessage(
- new Message(
- "Found @AspectJ annotations in a non @Aspect type '" + type.getName() + "'",
- IMessage.WARNING,
- null,
- type.getSourceLocation()
- )
- );
- ;// go ahead
- }
- // semantic check - advice must be public
- if (hasAtAspectJAnnotation && !struct.method.isPublic()) {
- msgHandler.handleMessage(
- new Message(
- "Found @AspectJ annotation on a non public advice '" + methodToString(struct.method) + "'",
- IMessage.ERROR,
- null,
- type.getSourceLocation()
- )
- );
- ;// go ahead
- }
- // semantic check for non around advice must return void
- if (hasAtAspectJAnnotationMustReturnVoid && !Type.VOID.equals(struct.method.getReturnType())) {
- msgHandler.handleMessage(
- new Message(
- "Found @AspectJ annotation on a non around advice not returning void '" + methodToString(struct.method) + "'",
- IMessage.ERROR,
- null,
- type.getSourceLocation()
- )
- );
- ;// go ahead
- }
-
-
- return struct.ajAttributes;
- }
-
- /**
- * Extract field level annotations and turn them into AjAttributes.
- *
- * @param field
- * @param type
- * @param context
- * @param msgHandler
- * @return list of AjAttributes, always empty for now
- */
- public static List readAj5FieldAttributes(Field field, ResolvedTypeX type, ISourceContext context,IMessageHandler msgHandler) {
- return Collections.EMPTY_LIST;
- }
-
- /**
- * Read @Aspect
- *
- * @param runtimeAnnotations
- * @param struct
- * @return true if found
- */
- private static boolean handleAspectAnnotation(RuntimeAnnotations runtimeAnnotations, AjAttributeStruct struct) {
- Annotation aspect = getAnnotation(runtimeAnnotations, "org.aspectj.lang.annotation.Aspect");
- if (aspect != null) {
- ElementNameValuePair aspectPerClause = getAnnotationElement(aspect, "value");
- if (aspectPerClause == null) {
- // defaults to singleton
- PerClause clause = new PerSingleton();
- clause.setLocation(struct.context, -1, -1);
- struct.ajAttributes.add(new AjAttribute.Aspect(clause));
- return true;
- } else {
- String perX = aspectPerClause.getValue().stringifyValue();
- final PerClause clause;
- if (perX == null || perX.length()<=0) {
- clause = new PerSingleton();
- } else {
- clause = parsePerClausePointcut(perX, struct);
- }
- clause.setLocation(struct.context, -1, -1);
- struct.ajAttributes.add(new AjAttribute.Aspect(clause));
- return true;
- }
- }
- return false;
- }
-
- /**
- * Read a perClause
- *
- * @param perClause like "pertarget(.....)"
- * @param struct for which we are parsing the per clause
- * @return a PerClause instance
- */
- private static PerClause parsePerClausePointcut(String perClause, AjAttributeStruct struct) {
- final String pointcut;
- if (perClause.startsWith(PerClause.KindAnnotationPrefix.PERCFLOW.getName())) {
- pointcut = PerClause.KindAnnotationPrefix.PERCFLOW.extractPointcut(perClause);
- return new PerCflow(Pointcut.fromString(pointcut), false);
- } else if (perClause.startsWith(PerClause.KindAnnotationPrefix.PERCFLOWBELOW.getName())) {
- pointcut = PerClause.KindAnnotationPrefix.PERCFLOWBELOW.extractPointcut(perClause);
- return new PerCflow(Pointcut.fromString(pointcut), true);
- } else if (perClause.startsWith(PerClause.KindAnnotationPrefix.PERTARGET.getName())) {
- pointcut = PerClause.KindAnnotationPrefix.PERTARGET.extractPointcut(perClause);
- return new PerObject(Pointcut.fromString(pointcut), false);
- } else if (perClause.startsWith(PerClause.KindAnnotationPrefix.PERTHIS.getName())) {
- pointcut = PerClause.KindAnnotationPrefix.PERTHIS.extractPointcut(perClause);
- return new PerObject(Pointcut.fromString(pointcut), true);
- } else if (perClause.startsWith(PerClause.KindAnnotationPrefix.PERTYPEWITHIN.getName())) {
- pointcut = PerClause.KindAnnotationPrefix.PERTYPEWITHIN.extractPointcut(perClause);
- return new PerTypeWithin(new PatternParser(pointcut).parseTypePattern());
- } else if (perClause.equalsIgnoreCase(PerClause.SINGLETON.getName() + "()")) {
- return new PerSingleton();
- }
- // could not parse the @AJ perclause
- struct.handler.handleMessage(
- new Message(
- "cannot read per clause from @Aspect: " + perClause,
- struct.enclosingType.getSourceLocation(),
- true
- )
- );
- throw new RuntimeException("cannot read perclause " + perClause);
- }
-
- /**
- * Read @DeclarePrecedence
- *
- * @param runtimeAnnotations
- * @param struct
- * @return true if found
- */
- private static boolean handlePrecedenceAnnotation(RuntimeAnnotations runtimeAnnotations, AjAttributeStruct struct) {
- Annotation aspect = getAnnotation(runtimeAnnotations, "org.aspectj.lang.annotation.DeclarePrecedence");
- if (aspect != null) {
- ElementNameValuePair precedence = getAnnotationElement(aspect, "value");
- if (precedence != null) {
- String precedencePattern = precedence.getValue().stringifyValue();
- PatternParser parser = new PatternParser(precedencePattern);
- DeclarePrecedence ajPrecedence = parser.parseDominates();
- struct.ajAttributes.add(new AjAttribute.DeclareAttribute(ajPrecedence));
- return true;
- }
- }
- return false;
- }
-
- /**
- * Read @Before
- *
- * @param runtimeAnnotations
- * @param struct
- * @return true if found
- */
- private static boolean handleBeforeAnnotation(RuntimeAnnotations runtimeAnnotations, AjAttributeMethodStruct struct, ResolvedPointcutDefinition preResolvedPointcut) {
- Annotation before = getAnnotation(runtimeAnnotations, "org.aspectj.lang.annotation.Before");
- if (before != null) {
- ElementNameValuePair beforeAdvice = getAnnotationElement(before, "value");
- if (beforeAdvice != null) {
- // this/target/args binding
- FormalBinding[] bindings = new org.aspectj.weaver.patterns.FormalBinding[0];
- try {
- bindings = extractBindings(struct);
- } catch (UnreadableDebugInfo unreadableDebugInfo) {
- return false;
- }
- IScope binding = new BindingScope(
- struct.enclosingType,
- bindings
- );
-
- // joinpoint, staticJoinpoint binding
- int extraArgument = extractExtraArgument(struct.method);
-
- Pointcut pc = null;
- if (preResolvedPointcut != null) {
- pc = preResolvedPointcut.getPointcut();
- } else {
- pc = Pointcut.fromString(beforeAdvice.getValue().stringifyValue()).resolve(binding);
- }
- setIgnoreUnboundBindingNames(pc, bindings);
-
- struct.ajAttributes.add(new AjAttribute.AdviceAttribute(
- AdviceKind.Before,
- pc,
- extraArgument,
- -1,
- -1,
- struct.context
- )
- );
- return true;
- }
- }
- return false;
- }
-
- /**
- * Read @After
- *
- * @param runtimeAnnotations
- * @param struct
- * @return true if found
- */
- private static boolean handleAfterAnnotation(RuntimeAnnotations runtimeAnnotations, AjAttributeMethodStruct struct, ResolvedPointcutDefinition preResolvedPointcut) {
- Annotation after = getAnnotation(runtimeAnnotations, "org.aspectj.lang.annotation.After");
- if (after != null) {
- ElementNameValuePair afterAdvice = getAnnotationElement(after, "value");
- if (afterAdvice != null) {
- // this/target/args binding
- FormalBinding[] bindings = new org.aspectj.weaver.patterns.FormalBinding[0];
- try {
- bindings = extractBindings(struct);
- } catch (UnreadableDebugInfo unreadableDebugInfo) {
- return false;
- }
- IScope binding = new BindingScope(
- struct.enclosingType,
- bindings
- );
-
- // joinpoint, staticJoinpoint binding
- int extraArgument = extractExtraArgument(struct.method);
-
- Pointcut pc = null;
- if (preResolvedPointcut != null) {
- pc = preResolvedPointcut.getPointcut();
- } else {
- pc = Pointcut.fromString(afterAdvice.getValue().stringifyValue()).resolve(binding);
- }
- setIgnoreUnboundBindingNames(pc, bindings);
-
- struct.ajAttributes.add(new AjAttribute.AdviceAttribute(
- AdviceKind.After,
- pc,
- extraArgument,
- -1,
- -1,
- struct.context
- )
- );
- return true;
- }
- }
- return false;
- }
-
- /**
- * Read @AfterReturning
- *
- * @param runtimeAnnotations
- * @param struct
- * @return true if found
- */
- private static boolean handleAfterReturningAnnotation(RuntimeAnnotations runtimeAnnotations, AjAttributeMethodStruct struct, ResolvedPointcutDefinition preResolvedPointcut) {
- Annotation after = getAnnotation(runtimeAnnotations, "org.aspectj.lang.annotation.AfterReturning");
- if (after != null) {
- ElementNameValuePair annValue = getAnnotationElement(after, "value");
- ElementNameValuePair annPointcut = getAnnotationElement(after, "pointcut");
- ElementNameValuePair annReturned = getAnnotationElement(after, "returning");
-
- // extract the pointcut and returned type/binding - do some checks
- String pointcut = null;
- String returned = null;
- if ((annValue!=null && annPointcut!=null) || (annValue==null && annPointcut==null)) {
- struct.handler.handleMessage(
- new Message(
- "@AfterReturning: either 'value' or 'poincut' must be provided, not both: " + methodToString(struct.method),
- struct.enclosingType.getSourceLocation(),
- true
- )
- );
- return false;
- }
- if (annValue != null) {
- pointcut = annValue.getValue().stringifyValue();
- } else {
- pointcut = annPointcut.getValue().stringifyValue();
- }
- if (isNullOrEmpty(pointcut)) {
- struct.handler.handleMessage(
- new Message(
- "@AfterReturning: either 'value' or 'poincut' must be provided, not both: " + methodToString(struct.method),
- struct.enclosingType.getSourceLocation(),
- true
- )
- );
- return false;
- }
- if (annReturned!=null) {
- returned = annReturned.getValue().stringifyValue();
- if (isNullOrEmpty(returned))
- returned = null;
- }
-
- // this/target/args binding
- // exclude the return binding from the pointcut binding since it is an extraArg binding
- FormalBinding[] bindings = new org.aspectj.weaver.patterns.FormalBinding[0];
- try {
- bindings = (returned==null?extractBindings(struct):extractBindings(struct, returned));
- } catch (UnreadableDebugInfo unreadableDebugInfo) {
- return false;
- }
- IScope binding = new BindingScope(
- struct.enclosingType,
- bindings
- );
-
- // joinpoint, staticJoinpoint binding
- int extraArgument = extractExtraArgument(struct.method);
-
- // return binding
- if (returned != null) {
- extraArgument |= Advice.ExtraArgument;
- }
-
- Pointcut pc = null;
- if (preResolvedPointcut != null) {
- pc = preResolvedPointcut.getPointcut();
- } else {
- pc = Pointcut.fromString(pointcut).resolve(binding);
- }
- setIgnoreUnboundBindingNames(pc, bindings);
- pc.setLocation(struct.enclosingType.getSourceContext(), 0, 0);//TODO method location ?
-
- struct.ajAttributes.add(new AjAttribute.AdviceAttribute(
- AdviceKind.AfterReturning,
- pc,
- extraArgument,
- -1,
- -1,
- struct.context
- )
- );
- return true;
- }
- return false;
- }
-
- /**
- * Read @AfterThrowing
- *
- * @param runtimeAnnotations
- * @param struct
- * @return true if found
- */
- private static boolean handleAfterThrowingAnnotation(RuntimeAnnotations runtimeAnnotations, AjAttributeMethodStruct struct, ResolvedPointcutDefinition preResolvedPointcut) {
- Annotation after = getAnnotation(runtimeAnnotations, "org.aspectj.lang.annotation.AfterThrowing");
- if (after != null) {
- ElementNameValuePair annValue = getAnnotationElement(after, "value");
- ElementNameValuePair annPointcut = getAnnotationElement(after, "pointcut");
- ElementNameValuePair annThrowned = getAnnotationElement(after, "throwing");
-
- // extract the pointcut and throwned type/binding - do some checks
- String pointcut = null;
- String throwned = null;
- if ((annValue!=null && annPointcut!=null) || (annValue==null && annPointcut==null)) {
- struct.handler.handleMessage(
- new Message(
- "@AfterThrowing: either 'value' or 'poincut' must be provided, not both: " + methodToString(struct.method),
- struct.enclosingType.getSourceLocation(),
- true
- )
- );
- return false;
- }
- if (annValue != null) {
- pointcut = annValue.getValue().stringifyValue();
- } else {
- pointcut = annPointcut.getValue().stringifyValue();
- }
- if (isNullOrEmpty(pointcut)) {
- struct.handler.handleMessage(
- new Message(
- "@AfterThrowing: either 'value' or 'poincut' must be provided, not both: " + methodToString(struct.method),
- struct.enclosingType.getSourceLocation(),
- true
- )
- );
- return false;
- }
- if (annThrowned!=null) {
- throwned = annThrowned.getValue().stringifyValue();
- if (isNullOrEmpty(throwned))
- throwned = null;
- }
-
- // this/target/args binding
- // exclude the throwned binding from the pointcut binding since it is an extraArg binding
- FormalBinding[] bindings = new org.aspectj.weaver.patterns.FormalBinding[0];
- try {
- bindings = (throwned==null?extractBindings(struct):extractBindings(struct, throwned));
- } catch (UnreadableDebugInfo unreadableDebugInfo) {
- return false;
- }
- IScope binding = new BindingScope(
- struct.enclosingType,
- bindings
- );
-
- // joinpoint, staticJoinpoint binding
- int extraArgument = extractExtraArgument(struct.method);
-
- // return binding
- if (throwned != null) {
- extraArgument |= Advice.ExtraArgument;
- }
-
- Pointcut pc = null;
- if (preResolvedPointcut != null) {
- pc = preResolvedPointcut.getPointcut();
- } else {
- pc = Pointcut.fromString(pointcut).resolve(binding);
- }
- setIgnoreUnboundBindingNames(pc, bindings);
-
- struct.ajAttributes.add(new AjAttribute.AdviceAttribute(
- AdviceKind.AfterThrowing,
- pc,
- extraArgument,
- -1,
- -1,
- struct.context
- )
- );
- return true;
- }
- return false;
- }
-
- /**
- * Read @Around
- *
- * @param runtimeAnnotations
- * @param struct
- * @return true if found
- */
- private static boolean handleAroundAnnotation(RuntimeAnnotations runtimeAnnotations, AjAttributeMethodStruct struct, ResolvedPointcutDefinition preResolvedPointcut) {
- Annotation around = getAnnotation(runtimeAnnotations, "org.aspectj.lang.annotation.Around");
- if (around != null) {
- ElementNameValuePair aroundAdvice = getAnnotationElement(around, "value");
- if (aroundAdvice != null) {
- // this/target/args binding
- FormalBinding[] bindings = new org.aspectj.weaver.patterns.FormalBinding[0];
- try {
- bindings = extractBindings(struct);
- } catch (UnreadableDebugInfo unreadableDebugInfo) {
- return false;
- }
- IScope binding = new BindingScope(
- struct.enclosingType,
- bindings
- );
-
- // joinpoint, staticJoinpoint binding
- int extraArgument = extractExtraArgument(struct.method);
-
- Pointcut pc = null;
- if (preResolvedPointcut != null) {
- pc = preResolvedPointcut.getPointcut();
- } else {
- pc = Pointcut.fromString(aroundAdvice.getValue().stringifyValue()).resolve(binding);
- }
- setIgnoreUnboundBindingNames(pc, bindings);
-
- struct.ajAttributes.add(new AjAttribute.AdviceAttribute(
- AdviceKind.Around,
- pc,
- extraArgument,
- -1,
- -1,
- struct.context
- )
- );
- return true;
- }
- }
- return false;
- }
-
- /**
- * Read @Pointcut and handle the resolving in a lazy way to deal with pointcut references
- *
- * @param runtimeAnnotations
- * @param struct
- */
- private static void handlePointcutAnnotation(RuntimeAnnotations runtimeAnnotations, AjAttributeMethodStruct struct) {
- Annotation pointcut = getAnnotation(runtimeAnnotations, "org.aspectj.lang.annotation.Pointcut");
- if (pointcut != null) {
- ElementNameValuePair pointcutExpr = getAnnotationElement(pointcut, "value");
- if (pointcutExpr != null) {
-
- // semantic check: the method must return void
- if (!Type.VOID.equals(struct.method.getReturnType())) {
- struct.handler.handleMessage(
- new Message(
- "Found @Pointcut on a method not returning void '" + methodToString(struct.method) + "'",
- IMessage.WARNING,
- null,
- struct.enclosingType.getSourceLocation()//TODO method loc instead how ?
- )
- );
- //TODO AV : Andy - should we stop ?
- return;
- }
- // semantic check: the method must not throw anything
- if (struct.method.getExceptionTable() != null) {
- struct.handler.handleMessage(
- new Message(
- "Found @Pointcut on a method throwing exception '" + methodToString(struct.method) + "'",
- IMessage.WARNING,
- null,
- struct.enclosingType.getSourceLocation()//TODO method loc instead how ?
- )
- );
- //TODO AV : Andy - should we stop ?
- return;
- }
-
- // this/target/args binding
- final IScope binding;
- try {
- binding = new BindingScope(
- struct.enclosingType,
- extractBindings(struct)
- );
- } catch(UnreadableDebugInfo e) {
- return;
- }
-
- TypeX[] argumentTypes = new TypeX[struct.method.getArgumentTypes().length];
- for (int i = 0; i < argumentTypes.length; i++) {
- argumentTypes[i] = TypeX.forSignature(struct.method.getArgumentTypes()[i].getSignature());
- }
-
- // use a LazyResolvedPointcutDefinition so that the pointcut is resolved lazily
- // since for it to be resolved, we will need other pointcuts to be registered as well
- try {
- struct.ajAttributes.add(new AjAttribute.PointcutDeclarationAttribute(
- new LazyResolvedPointcutDefinition(
- struct.enclosingType,
- struct.method.getModifiers(),
- struct.method.getName(),
- argumentTypes,
- Pointcut.fromString(pointcutExpr.getValue().stringifyValue()),
- binding
- )
- ));
- } catch (ParserException e) {
- struct.handler.handleMessage(
- new Message(
- "Cannot parse @Pointcut '" + pointcutExpr.getValue().stringifyValue() + "'",
- IMessage.ERROR,
- e,
- struct.enclosingType.getSourceLocation()//TODO method loc instead how ?
- )
- );
- return;
- }
- }
- }
- }
-
- /**
- * Read @DeclareError, @DeclareWarning
- *
- * @param runtimeAnnotations
- * @param struct
- * @return true if found
- */
- private static boolean handleDeclareErrorOrWarningAnnotation(RuntimeAnnotations runtimeAnnotations, AjAttributeFieldStruct struct) {
- Annotation error = getAnnotation(runtimeAnnotations, "org.aspectj.lang.annotation.DeclareError");
- boolean hasError = false;
- if (error != null) {
- ElementNameValuePair declareError = getAnnotationElement(error, "value");
- if (declareError != null) {
- if (!"Ljava/lang/String;".equals(struct.field.getSignature()) || struct.field.getConstantValue()==null) {
- struct.handler.handleMessage(
- new Message(
- "@DeclareError used on a non String constant field " + fieldToString(struct.field),
- struct.enclosingType.getSourceLocation(),
- true
- ));
- return false;
- }
- FormalBinding[] bindings = new org.aspectj.weaver.patterns.FormalBinding[0];
- IScope binding = new BindingScope(
- struct.enclosingType,
- bindings
- );
- Pointcut pc = Pointcut.fromString(declareError.getValue().stringifyValue()).resolve(binding);
- struct.ajAttributes.add(new AjAttribute.DeclareAttribute(
- new DeclareErrorOrWarning(true, pc, struct.field.getConstantValue().toString())
- ));
- return hasError = true;
- }
- }
- Annotation warning = getAnnotation(runtimeAnnotations, "org.aspectj.lang.annotation.DeclareWarning");
- boolean hasWarning = false;
- if (warning != null) {
- ElementNameValuePair declareWarning = getAnnotationElement(warning, "value");
- if (declareWarning != null) {
- if (!"Ljava/lang/String;".equals(struct.field.getSignature()) || struct.field.getConstantValue()==null) {
- struct.handler.handleMessage(
- new Message(
- "@DeclareWarning used on a non String constant field " + fieldToString(struct.field),
- struct.enclosingType.getSourceLocation(),
- true
- ));
- return false;
- }
- FormalBinding[] bindings = new org.aspectj.weaver.patterns.FormalBinding[0];
- IScope binding = new BindingScope(
- struct.enclosingType,
- bindings
- );
- Pointcut pc = Pointcut.fromString(declareWarning.getValue().stringifyValue()).resolve(binding);
- struct.ajAttributes.add(new AjAttribute.DeclareAttribute(
- new DeclareErrorOrWarning(false, pc, struct.field.getConstantValue().toString())
- ));
- return hasWarning = true;
- }
- }
- return hasError || hasWarning;
- }
-
- /**
- * Returns a readable representation of a method.
- * Method.toString() is not suitable.
- *
- * @param method
- * @return
- */
- private static String methodToString(Method method) {
- StringBuffer sb = new StringBuffer();
- sb.append(method.getName());
- sb.append(method.getSignature());
- return sb.toString();
- }
-
- /**
- * Returns a readable representation of a field.
- * Field.toString() is not suitable.
- *
- * @param field
- * @return
- */
- private static String fieldToString(Field field) {
- StringBuffer sb = new StringBuffer();
- sb.append(field.getName()).append(' ');
- sb.append(field.getSignature());
- return sb.toString();
- }
-
- /**
- * Build the bindings for a given method (pointcut / advice)
- *
- * @param struct
- * @return null if no debug info is available
- */
- private static FormalBinding[] extractBindings(AjAttributeMethodStruct struct)
- throws UnreadableDebugInfo {
- Method method = struct.method;
- String[] argumentNames = struct.getArgumentNames();
-
- // assert debug info was here
- if (argumentNames.length != method.getArgumentTypes().length) {
- struct.handler.handleMessage(
- new Message(
- "Cannot read debug info for @Aspect '" + struct.enclosingType.getName() + "'"
- + " (please compile with 'javac -g' or '<javac debug='true'.../>' in Ant)",
- IMessage.FAIL,
- null,
- struct.enclosingType.getSourceLocation()
- )
- );
- throw new UnreadableDebugInfo();
- }
-
- List bindings = new ArrayList();
- for (int i = 0; i < argumentNames.length; i++) {
- String argumentName = argumentNames[i];
- TypeX argumentType = TypeX.forSignature(method.getArgumentTypes()[i].getSignature());
-
- // do not bind JoinPoint / StaticJoinPoint / EnclosingStaticJoinPoint
- // TODO solve me : this means that the JP/SJP/ESJP cannot appear as binding
- // f.e. when applying advice on advice etc
- if ((TYPEX_JOINPOINT.equals(argumentType)
- || TYPEX_PROCEEDINGJOINPOINT.equals(argumentType)
- || TYPEX_STATICJOINPOINT.equals(argumentType)
- || TYPEX_ENCLOSINGSTATICJOINPOINT.equals(argumentType)
- || AjcMemberMaker.AROUND_CLOSURE_TYPE.equals(argumentType))) {
- //continue;// skip
- bindings.add(new FormalBinding.ImplicitFormalBinding(argumentType, argumentName, i));
- } else {
- bindings.add(new FormalBinding(argumentType, argumentName, i));
- }
- }
-
- return (FormalBinding[]) bindings.toArray(new FormalBinding[]{});
- }
-
- //FIXME alex deal with exclude index
- private static FormalBinding[] extractBindings(AjAttributeMethodStruct struct, String excludeFormal)
- throws UnreadableDebugInfo {
- FormalBinding[] bindings = extractBindings(struct);
- int excludeIndex = -1;
- for (int i = 0; i < bindings.length; i++) {
- FormalBinding binding = bindings[i];
- if (binding.getName().equals(excludeFormal)) {
- excludeIndex = i;
- bindings[i] = new FormalBinding.ImplicitFormalBinding(binding.getType(), binding.getName(), binding.getIndex());
- break;
- }
- }
- return bindings;
-//
-// if (excludeIndex >= 0) {
-// FormalBinding[] bindingsFiltered = new FormalBinding[bindings.length-1];
-// int k = 0;
-// for (int i = 0; i < bindings.length; i++) {
-// if (i == excludeIndex) {
-// ;
-// } else {
-// bindingsFiltered[k] = new FormalBinding(bindings[i].getType(), bindings[i].getName(), k);
-// k++;
-// }
-// }
-// return bindingsFiltered;
-// } else {
-// return bindings;
-// }
- }
-
-
- /**
- * Compute the flag for the xxxJoinPoint extra argument
- *
- * @param method
- * @return
- */
- private static int extractExtraArgument(Method method) {
- int extraArgument = 0;
- Type[] methodArgs = method.getArgumentTypes();
- for (int i = 0; i < methodArgs.length; i++) {
- String methodArg = methodArgs[i].getSignature();
- if (TYPEX_JOINPOINT.getSignature().equals(methodArg)) {
- extraArgument |= Advice.ThisJoinPoint;
- } else if (TYPEX_PROCEEDINGJOINPOINT.getSignature().equals(methodArg)) {
- extraArgument |= Advice.ThisJoinPoint;
- } else if (TYPEX_STATICJOINPOINT.getSignature().equals(methodArg)) {
- extraArgument |= Advice.ThisJoinPointStaticPart;
- } else if (TYPEX_ENCLOSINGSTATICJOINPOINT.getSignature().equals(methodArg)) {
- extraArgument |= Advice.ThisEnclosingJoinPointStaticPart;
- }
- }
- return extraArgument;
- }
-
- /**
- * Returns the runtime (RV/RIV) annotation of type annotationType or null if no such annotation
- *
- * @param rvs
- * @param annotationType
- * @return
- */
- private static Annotation getAnnotation(RuntimeAnnotations rvs, String annotationType) {
- for (Iterator iterator = rvs.getAnnotations().iterator(); iterator.hasNext();) {
- Annotation rv = (Annotation) iterator.next();
- if (annotationType.equals(rv.getTypeName())) {
- return rv;
- }
- }
- return null;
- }
-
- /**
- * Returns the value of a given element of an annotation or null if not found
- * Caution: Does not handles default value.
- *
- * @param annotation
- * @param elementName
- * @return
- */
- private static ElementNameValuePair getAnnotationElement(Annotation annotation, String elementName) {
- for (Iterator iterator1 = annotation.getValues().iterator(); iterator1.hasNext();) {
- ElementNameValuePair element = (ElementNameValuePair) iterator1.next();
- if (elementName.equals(element.getNameString())) {
- return element;
- }
- }
- return null;
- }
-
- /**
- * Extract the method argument names as in source from debug info
- * returns an empty array upon inconsistency
- *
- * @param method
- * @return
- */
- private static String[] getMethodArgumentNamesAsInSource(Method method) {
- if (method.getArgumentTypes().length == 0) {
- return EMPTY_STRINGS;
- }
-
- final int startAtStackIndex = method.isStatic()?0:1;
- final List arguments = new ArrayList();
- LocalVariableTable lt = (LocalVariableTable) method.getLocalVariableTable();
- if (lt != null) {
- for (int j = 0; j < lt.getLocalVariableTable().length; j++) {
- LocalVariable localVariable = lt.getLocalVariableTable()[j];
- if (localVariable.getStartPC() == 0) {
- if (localVariable.getIndex() >= startAtStackIndex) {
- arguments.add(new MethodArgument(localVariable.getName(), localVariable.getIndex()));
- }
- }
- }
- }
-
- if (arguments.size() != method.getArgumentTypes().length) {
- //throw new RuntimeException("cannot access debug info on " + method);
- return EMPTY_STRINGS;
- }
-
- // sort by index
- Collections.sort(arguments, new Comparator() {
- public int compare(Object o, Object o1) {
- MethodArgument mo = (MethodArgument)o;
- MethodArgument mo1 = (MethodArgument) o1;
- if (mo.indexOnStack == mo1.indexOnStack) {
- return 0;
- } else if (mo.indexOnStack > mo1.indexOnStack) {
- return 1;
- } else {
- return -1;
- }
- }
- });
- String[] argumentNames = new String[arguments.size()];
- int i = 0;
- for (Iterator iterator = arguments.iterator(); iterator.hasNext(); i++) {
- MethodArgument methodArgument = (MethodArgument) iterator.next();
- argumentNames[i] = methodArgument.name;
- }
- return argumentNames;
- }
-
- /**
- * A method argument, used for sorting by indexOnStack (ie order in signature)
- *
- * @author <a href="mailto:alex AT gnilux DOT com">Alexandre Vasseur</a>
- */
- private static class MethodArgument {
- String name;
- int indexOnStack;
- public MethodArgument(String name, int indexOnStack) {
- this.name = name;
- this.indexOnStack = indexOnStack;
- }
- }
-
- /**
- * BindingScope that knows the enclosingType, which is needed for pointcut reference resolution
- *
- * @author <a href="mailto:alex AT gnilux DOT com">Alexandre Vasseur</a>
- */
- public static class BindingScope extends SimpleScope {
- private ResolvedTypeX m_enclosingType;
-
- public BindingScope(ResolvedTypeX type, FormalBinding[] bindings) {
- super(type.getWorld(), bindings);
- m_enclosingType = type;
- }
-
- public ResolvedTypeX getEnclosingType() {
- return m_enclosingType;
- }
- }
-
- /**
- * LazyResolvedPointcutDefinition lazyly resolve the pointcut so that we have time to register all
- * pointcut referenced before pointcut resolution happens
- *
- * @author <a href="mailto:alex AT gnilux DOT com">Alexandre Vasseur</a>
- */
- public static class LazyResolvedPointcutDefinition extends ResolvedPointcutDefinition {
- private Pointcut m_pointcutUnresolved;
- private IScope m_binding;
-
- private Pointcut m_lazyPointcut = null;
-
- public LazyResolvedPointcutDefinition(ResolvedTypeX declaringType, int modifiers, String name, TypeX[] parameterTypes,
- Pointcut pointcut, IScope binding) {
- super(declaringType, modifiers, name, parameterTypes, null);
- m_pointcutUnresolved = pointcut;
- m_binding = binding;
- m_pointcutUnresolved.setLocation(declaringType.getSourceContext(), 0, 0);
- }
-
- public Pointcut getPointcut() {
- if (m_lazyPointcut == null) {
- m_lazyPointcut = m_pointcutUnresolved.resolve(m_binding);
- m_lazyPointcut.copyLocationFrom(m_pointcutUnresolved);
- }
- return m_lazyPointcut;
- }
- }
-
- /**
- * Helper to test empty strings
- * @param s
- * @return
- */
- private static boolean isNullOrEmpty(String s) {
- return (s==null || s.length()<=0);
- }
-
- /**
- * Set the pointcut bindings for which to ignore unbound issues, so that we can implicitly bind
- * xxxJoinPoint for @AJ advices
- *
- * @param pointcut
- * @param bindings
- */
- private static void setIgnoreUnboundBindingNames(Pointcut pointcut, FormalBinding[] bindings) {
- // register ImplicitBindings as to be ignored since unbound
- // TODO is it likely to fail in a bad way if f.e. this(jp) etc ?
- List ignores = new ArrayList();
- for (int i = 0; i < bindings.length; i++) {
- FormalBinding formalBinding = bindings[i];
- if (formalBinding instanceof FormalBinding.ImplicitFormalBinding) {
- ignores.add(formalBinding.getName());
- }
- }
- pointcut.m_ignoreUnboundBindingForNames = (String[])ignores.toArray(new String[ignores.size()]);
- }
-
- /**
- * A check exception when we cannot read debug info (needed for formal binding)
- */
- private static class UnreadableDebugInfo extends Exception {
- }
-}
+++ /dev/null
-/*******************************************************************************
- * Copyright (c) 2005 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://eclipse.org/legal/epl-v10.html
- *
- * Contributors:
- * initial implementation Alexandre Vasseur
- *******************************************************************************/
-package org.aspectj.weaver.ataspectj;
-
-import org.aspectj.weaver.ResolvedMember;
-import org.aspectj.weaver.TypeX;
-import org.aspectj.weaver.Member;
-import org.aspectj.weaver.ResolvedTypeX;
-
-import java.lang.reflect.Modifier;
-
-/**
- * Addition to AjcMemberMaker for @Aj aspect
- * Should end up there
- *
- * @author <a href="mailto:alex AT gnilux DOT com">Alexandre Vasseur</a>
- */
-public class Ajc5MemberMaker {
-
- public final static TypeX ASPECT = TypeX.forName("org.aspectj.lang.annotation.Aspect");
-
- /**
- * Returns true if the given aspect is an @AJ aspect
- *
- * @param aspectType
- * @return
- */
- public static boolean isAnnotationStyleAspect(ResolvedTypeX aspectType) {
- if (aspectType != null) {
- if (aspectType.isAspect()) {
- return aspectType.isAnnotationStyleAspect();
- }
- }
- return false;
- }
-
- //temp proto code for aspectOf without pre-processing
- public static ResolvedMember perSingletonAspectOfMethod(TypeX declaringType) {
- return new ResolvedMember(
- Member.METHOD,
- TypeX.forName("alex.lang.Aspects"),
- Modifier.PUBLIC | Modifier.STATIC,
- "aspectOf$singleton",
- "(Ljava/lang/String;Ljava/lang/Class;)Ljava/lang/Object;"
- );
-
-
- }
-
-}
--- /dev/null
+/*******************************************************************************
+ * Copyright (c) 2005 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://eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * initial implementation Alexandre Vasseur
+ *******************************************************************************/
+package org.aspectj.weaver.bcel;
+
+import org.aspectj.apache.bcel.classfile.Attribute;
+import org.aspectj.apache.bcel.classfile.Field;
+import org.aspectj.apache.bcel.classfile.JavaClass;
+import org.aspectj.apache.bcel.classfile.LocalVariable;
+import org.aspectj.apache.bcel.classfile.LocalVariableTable;
+import org.aspectj.apache.bcel.classfile.Method;
+import org.aspectj.apache.bcel.classfile.annotation.Annotation;
+import org.aspectj.apache.bcel.classfile.annotation.ElementNameValuePair;
+import org.aspectj.apache.bcel.classfile.annotation.RuntimeAnnotations;
+import org.aspectj.apache.bcel.classfile.annotation.RuntimeVisibleAnnotations;
+import org.aspectj.apache.bcel.generic.Type;
+import org.aspectj.bridge.IMessage;
+import org.aspectj.bridge.IMessageHandler;
+import org.aspectj.bridge.Message;
+import org.aspectj.weaver.Advice;
+import org.aspectj.weaver.AdviceKind;
+import org.aspectj.weaver.AjAttribute;
+import org.aspectj.weaver.AjcMemberMaker;
+import org.aspectj.weaver.ISourceContext;
+import org.aspectj.weaver.NameMangler;
+import org.aspectj.weaver.ResolvedPointcutDefinition;
+import org.aspectj.weaver.ResolvedTypeX;
+import org.aspectj.weaver.TypeX;
+import org.aspectj.weaver.patterns.DeclareErrorOrWarning;
+import org.aspectj.weaver.patterns.DeclarePrecedence;
+import org.aspectj.weaver.patterns.FormalBinding;
+import org.aspectj.weaver.patterns.IScope;
+import org.aspectj.weaver.patterns.ParserException;
+import org.aspectj.weaver.patterns.PatternParser;
+import org.aspectj.weaver.patterns.PerCflow;
+import org.aspectj.weaver.patterns.PerClause;
+import org.aspectj.weaver.patterns.PerObject;
+import org.aspectj.weaver.patterns.PerSingleton;
+import org.aspectj.weaver.patterns.PerTypeWithin;
+import org.aspectj.weaver.patterns.Pointcut;
+import org.aspectj.weaver.patterns.SimpleScope;
+import org.aspectj.weaver.patterns.TypePattern;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.Iterator;
+import java.util.List;
+
+/**
+ * Annotation defined aspect reader.
+ * <p/>
+ * It reads the Java 5 annotations and turns them into AjAttributes
+ *
+ * @author <a href="mailto:alex AT gnilux DOT com">Alexandre Vasseur</a>
+ */
+public class AtAjAttributes {
+
+ private final static List EMPTY_LIST = new ArrayList();
+ private final static String[] EMPTY_STRINGS = new String[0];
+ private final static String VALUE = "value";
+ private final static String POINTCUT = "pointcut";
+ private final static String THROWING = "throwing";
+ private final static String RETURNING = "returning";
+ private final static String STRING_DESC = "Ljava/lang/String;";
+
+ /**
+ * A struct that allows to add extra arguments without always breaking the API
+ *
+ * @author <a href="mailto:alex AT gnilux DOT com">Alexandre Vasseur</a>
+ */
+ private static class AjAttributeStruct {
+
+ /**
+ * The list of AjAttribute.XXX that we are populating from the @AJ read
+ */
+ List ajAttributes = new ArrayList();
+
+ /**
+ * The resolved type (class) for which we are reading @AJ for (be it class, method, field annotations)
+ */
+ final ResolvedTypeX enclosingType;
+
+ final ISourceContext context;
+ final IMessageHandler handler;
+
+ public AjAttributeStruct(ResolvedTypeX type, ISourceContext sourceContext, IMessageHandler messageHandler) {
+ enclosingType = type;
+ context = sourceContext;
+ handler = messageHandler;
+ }
+ }
+
+ /**
+ * A struct when we read @AJ on method
+ *
+ * @author <a href="mailto:alex AT gnilux DOT com">Alexandre Vasseur</a>
+ */
+ private static class AjAttributeMethodStruct extends AjAttributeStruct {
+
+ /**
+ * Argument names as they appear in the SOURCE code, ordered, and lazyly populated
+ * Used to do formal binding
+ */
+ private String[] m_argumentNamesLazy = null;
+
+ final Method method;
+
+ public AjAttributeMethodStruct(Method method, ResolvedTypeX type, ISourceContext sourceContext, IMessageHandler messageHandler) {
+ super(type, sourceContext, messageHandler);
+ this.method = method;
+ }
+
+ public String[] getArgumentNames() {
+ if (m_argumentNamesLazy == null) {
+ m_argumentNamesLazy = getMethodArgumentNamesAsInSource(method);
+ }
+ return m_argumentNamesLazy;
+ }
+ }
+
+ /**
+ * A struct when we read @AJ on field
+ *
+ * @author <a href="mailto:alex AT gnilux DOT com">Alexandre Vasseur</a>
+ */
+ private static class AjAttributeFieldStruct extends AjAttributeStruct {
+
+ final Field field;
+
+ public AjAttributeFieldStruct(Field field, ResolvedTypeX type, ISourceContext sourceContext, IMessageHandler messageHandler) {
+ super(type, sourceContext, messageHandler);
+ this.field = field;
+ }
+ }
+
+ /**
+ * Annotations are RuntimeVisible only. This allow us to not visit RuntimeInvisible ones.
+ *
+ * @param attribute
+ * @return
+ */
+ public static boolean acceptAttribute(Attribute attribute) {
+ return (attribute instanceof RuntimeVisibleAnnotations);
+ }
+
+ /**
+ * Extract class level annotations and turn them into AjAttributes.
+ *
+ * @param javaClass
+ * @param type
+ * @param context
+ * @param msgHandler
+ * @return list of AjAttributes
+ */
+ public static List readAj5ClassAttributes(JavaClass javaClass, ResolvedTypeX type, ISourceContext context, IMessageHandler msgHandler, boolean isCodeStyleAspect) {
+ AjAttributeStruct struct = new AjAttributeStruct(type, context, msgHandler);
+ Attribute[] attributes = javaClass.getAttributes();
+ boolean hasAtAspectAnnotation = false;
+ boolean hasAtPrecedenceAnnotation = false;
+
+ for (int i = 0; i < attributes.length; i++) {
+ Attribute attribute = attributes[i];
+ if (acceptAttribute(attribute)) {
+ RuntimeAnnotations rvs = (RuntimeAnnotations) attribute;
+ // we don't need to look for several attribute occurence since it cannot happen as per JSR175
+ if (!isCodeStyleAspect) {
+ hasAtAspectAnnotation = handleAspectAnnotation(rvs, struct);
+ }
+ //TODO: below means mix style for @DeclarePrecedence - are we sure we want that ?
+ hasAtPrecedenceAnnotation = handlePrecedenceAnnotation(rvs, struct);
+ // there can only be one RuntimeVisible bytecode attribute
+ break;
+ }
+ }
+
+ // basic semantic check
+ //FIXME AV TBD could be skipped and silently ignore - TBD with Andy
+ if (hasAtPrecedenceAnnotation && !hasAtAspectAnnotation) {
+ msgHandler.handleMessage(
+ new Message(
+ "Found @DeclarePrecedence on a non @Aspect type '" + type.getName() + "'",
+ IMessage.WARNING,
+ null,
+ type.getSourceLocation()
+ )
+ );
+ // bypass what we have read
+ return EMPTY_LIST;
+ }
+ //FIXME turn on when ajcMightHaveAspect fixed
+// if (hasAtAspectAnnotation && type.isInterface()) {
+// msgHandler.handleMessage(
+// new Message(
+// "Found @Aspect on an interface type '" + type.getName() + "'",
+// IMessage.WARNING,
+// null,
+// type.getSourceLocation()
+// )
+// );
+// // bypass what we have read
+// return EMPTY_LIST;
+// }
+
+ // the following block will not detect @Pointcut in non @Aspect types for optimization purpose
+ // FIXME AV TBD with Andy
+ if (!hasAtAspectAnnotation) {
+ return EMPTY_LIST;
+ }
+
+ // code style pointcuts are class attributes
+ // we need to gather the @AJ pointcut right now and not at method level annotation extraction time
+ // in order to be able to resolve the pointcut references later on
+ //FIXME alex loop over class super class
+ //FIXME alex can that be too slow ?
+ for (int i = 0; i < javaClass.getMethods().length; i++) {
+ Method method = javaClass.getMethods()[i];
+ if (method.getName().startsWith(NameMangler.PREFIX)) continue; // already dealt with by ajc...
+ //FIXME alex optimize, this method struct will gets recreated for advice extraction
+ AjAttributeMethodStruct mstruct = new AjAttributeMethodStruct(method, type, context, msgHandler);
+ Attribute[] mattributes = method.getAttributes();
+
+ for (int j = 0; j < mattributes.length; j++) {
+ Attribute mattribute = mattributes[j];
+ if (acceptAttribute(mattribute)) {
+ RuntimeAnnotations mrvs = (RuntimeAnnotations) mattribute;
+ handlePointcutAnnotation(mrvs, mstruct);
+ // there can only be one RuntimeVisible bytecode attribute
+ break;
+ }
+ }
+ struct.ajAttributes.addAll(mstruct.ajAttributes);
+ }
+
+
+ // code style declare error / warning are class attributes
+ for (int i = 0; i < javaClass.getFields().length; i++) {
+ Field field = javaClass.getFields()[i];
+ if (field.getName().startsWith(NameMangler.PREFIX)) continue; // already dealt with by ajc...
+ //FIXME alex optimize, this method struct will gets recreated for advice extraction
+ AjAttributeFieldStruct fstruct = new AjAttributeFieldStruct(field, type, context, msgHandler);
+ Attribute[] fattributes = field.getAttributes();
+
+ for (int j = 0; j < fattributes.length; j++) {
+ Attribute fattribute = fattributes[j];
+ if (acceptAttribute(fattribute)) {
+ RuntimeAnnotations frvs = (RuntimeAnnotations) fattribute;
+ if (handleDeclareErrorOrWarningAnnotation(frvs, fstruct)) {
+ // semantic check - must be in an @Aspect [remove if previous block bypassed in advance]
+ if (!type.isAnnotationStyleAspect()) {
+ msgHandler.handleMessage(
+ new Message(
+ "Found @AspectJ annotations in a non @Aspect type '" + type.getName() + "'",
+ IMessage.WARNING,
+ null,
+ type.getSourceLocation()
+ )
+ );
+ ;// go ahead
+ }
+ }
+ // there can only be one RuntimeVisible bytecode attribute
+ break;
+ }
+ }
+ struct.ajAttributes.addAll(fstruct.ajAttributes);
+ }
+ return struct.ajAttributes;
+ }
+
+ /**
+ * Extract method level annotations and turn them into AjAttributes.
+ *
+ * @param method
+ * @param type
+ * @param context
+ * @param msgHandler
+ * @return list of AjAttributes
+ */
+ public static List readAj5MethodAttributes(Method method, ResolvedTypeX type, ResolvedPointcutDefinition preResolvedPointcut, ISourceContext context, IMessageHandler msgHandler) {
+ if (method.getName().startsWith(NameMangler.PREFIX)) return Collections.EMPTY_LIST; // already dealt with by ajc...
+
+ AjAttributeMethodStruct struct = new AjAttributeMethodStruct(method, type, context, msgHandler);
+ Attribute[] attributes = method.getAttributes();
+
+ // we remember if we found one @AJ annotation for minimal semantic error reporting
+ // the real reporting beeing done thru AJDT and the compiler mapping @AJ to AjAtttribute
+ // or thru APT
+ // FIXME AV we could actually skip the whole thing if type is not itself an @Aspect
+ // but then we would not see any warning. TBD with Andy
+ boolean hasAtAspectJAnnotation = false;
+ boolean hasAtAspectJAnnotationMustReturnVoid = false;
+ for (int i = 0; i < attributes.length; i++) {
+ Attribute attribute = attributes[i];
+ if (acceptAttribute(attribute)) {
+ RuntimeAnnotations rvs = (RuntimeAnnotations) attribute;
+ hasAtAspectJAnnotationMustReturnVoid = hasAtAspectJAnnotationMustReturnVoid || handleBeforeAnnotation(
+ rvs, struct, preResolvedPointcut
+ );
+ hasAtAspectJAnnotationMustReturnVoid = hasAtAspectJAnnotationMustReturnVoid || handleAfterAnnotation(
+ rvs, struct, preResolvedPointcut
+ );
+ hasAtAspectJAnnotationMustReturnVoid = hasAtAspectJAnnotationMustReturnVoid || handleAfterReturningAnnotation(
+ rvs, struct, preResolvedPointcut
+ );
+ hasAtAspectJAnnotationMustReturnVoid = hasAtAspectJAnnotationMustReturnVoid || handleAfterThrowingAnnotation(
+ rvs, struct, preResolvedPointcut
+ );
+ hasAtAspectJAnnotation = hasAtAspectJAnnotation || handleAroundAnnotation(
+ rvs, struct, preResolvedPointcut
+ );
+ // there can only be one RuntimeVisible bytecode attribute
+ break;
+ }
+ }
+ hasAtAspectJAnnotation = hasAtAspectJAnnotation || hasAtAspectJAnnotationMustReturnVoid;
+
+ // semantic check - must be in an @Aspect [remove if previous block bypassed in advance]
+ if (hasAtAspectJAnnotation && !type.isAnnotationStyleAspect()) {
+ msgHandler.handleMessage(
+ new Message(
+ "Found @AspectJ annotations in a non @Aspect type '" + type.getName() + "'",
+ IMessage.WARNING,
+ null,
+ type.getSourceLocation()
+ )
+ );
+ ;// go ahead
+ }
+ // semantic check - advice must be public
+ if (hasAtAspectJAnnotation && !struct.method.isPublic()) {
+ msgHandler.handleMessage(
+ new Message(
+ "Found @AspectJ annotation on a non public advice '" + methodToString(struct.method) + "'",
+ IMessage.ERROR,
+ null,
+ type.getSourceLocation()
+ )
+ );
+ ;// go ahead
+ }
+ // semantic check for non around advice must return void
+ if (hasAtAspectJAnnotationMustReturnVoid && !Type.VOID.equals(struct.method.getReturnType())) {
+ msgHandler.handleMessage(
+ new Message(
+ "Found @AspectJ annotation on a non around advice not returning void '" + methodToString(
+ struct.method
+ ) + "'",
+ IMessage.ERROR,
+ null,
+ type.getSourceLocation()
+ )
+ );
+ ;// go ahead
+ }
+
+
+ return struct.ajAttributes;
+ }
+
+ /**
+ * Extract field level annotations and turn them into AjAttributes.
+ *
+ * @param field
+ * @param type
+ * @param context
+ * @param msgHandler
+ * @return list of AjAttributes, always empty for now
+ */
+ public static List readAj5FieldAttributes(Field field, ResolvedTypeX type, ISourceContext context, IMessageHandler msgHandler) {
+ return Collections.EMPTY_LIST;
+ }
+
+ /**
+ * Read @Aspect
+ *
+ * @param runtimeAnnotations
+ * @param struct
+ * @return true if found
+ */
+ private static boolean handleAspectAnnotation(RuntimeAnnotations runtimeAnnotations, AjAttributeStruct struct) {
+ Annotation aspect = getAnnotation(runtimeAnnotations, AjcMemberMaker.ASPECT_ANNOTATION);
+ if (aspect != null) {
+ ElementNameValuePair aspectPerClause = getAnnotationElement(aspect, VALUE);
+ final PerClause perClause;
+ if (aspectPerClause == null) {
+ // defaults to singleton
+ perClause = new PerSingleton();
+ } else {
+ String perX = aspectPerClause.getValue().stringifyValue();
+ if (perX == null || perX.length() <= 0) {
+ perClause = new PerSingleton();
+ } else {
+ perClause = parsePerClausePointcut(perX, struct);
+ }
+ }
+ if (perClause == null) {
+ // could not parse it, ignore the aspect
+ return false;
+ } else {
+ perClause.setLocation(struct.context, -1, -1);
+ struct.ajAttributes.add(new AjAttribute.Aspect(perClause));
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Read a perClause, returns null on failure and issue messages
+ *
+ * @param perClauseString like "pertarget(.....)"
+ * @param struct for which we are parsing the per clause
+ * @return a PerClause instance
+ */
+ private static PerClause parsePerClausePointcut(String perClauseString, AjAttributeStruct struct) {
+ final String pointcutString;
+ Pointcut poincut = null;
+ TypePattern typePattern = null;
+ final PerClause perClause;
+ if (perClauseString.startsWith(PerClause.KindAnnotationPrefix.PERCFLOW.getName())) {
+ pointcutString = PerClause.KindAnnotationPrefix.PERCFLOW.extractPointcut(perClauseString);
+ poincut = parsePointcut(pointcutString, struct);
+ perClause = new PerCflow(poincut, false);
+ } else if (perClauseString.startsWith(PerClause.KindAnnotationPrefix.PERCFLOWBELOW.getName())) {
+ pointcutString = PerClause.KindAnnotationPrefix.PERCFLOWBELOW.extractPointcut(perClauseString);
+ poincut = parsePointcut(pointcutString, struct);
+ perClause = new PerCflow(poincut, true);
+ } else if (perClauseString.startsWith(PerClause.KindAnnotationPrefix.PERTARGET.getName())) {
+ pointcutString = PerClause.KindAnnotationPrefix.PERTARGET.extractPointcut(perClauseString);
+ poincut = parsePointcut(pointcutString, struct);
+ perClause = new PerObject(poincut, false);
+ } else if (perClauseString.startsWith(PerClause.KindAnnotationPrefix.PERTHIS.getName())) {
+ pointcutString = PerClause.KindAnnotationPrefix.PERTHIS.extractPointcut(perClauseString);
+ poincut = parsePointcut(pointcutString, struct);
+ perClause = new PerObject(poincut, true);
+ } else if (perClauseString.startsWith(PerClause.KindAnnotationPrefix.PERTYPEWITHIN.getName())) {
+ pointcutString = PerClause.KindAnnotationPrefix.PERTYPEWITHIN.extractPointcut(perClauseString);
+ typePattern = parseTypePattern(pointcutString, struct);
+ perClause = new PerTypeWithin(typePattern);
+ } else if (perClauseString.equalsIgnoreCase(PerClause.SINGLETON.getName() + "()")) {
+ perClause = new PerSingleton();
+ } else {
+ // could not parse the @AJ perclause - fallback to singleton and issue an error
+ reportError("@Aspect per clause cannot be read '" + perClauseString + "'", struct);
+ return null;
+ }
+
+ if (!PerClause.SINGLETON.equals(perClause.getKind())
+ && !PerClause.PERTYPEWITHIN.equals(perClause.getKind())
+ && poincut == null) {
+ // we could not parse the pointcut
+ return null;
+ }
+ if (PerClause.PERTYPEWITHIN.equals(perClause.getKind()) && typePattern == null) {
+ // we could not parse the type pattern
+ return null;
+ }
+ return perClause;
+ }
+
+ /**
+ * Read @DeclarePrecedence
+ *
+ * @param runtimeAnnotations
+ * @param struct
+ * @return true if found
+ */
+ private static boolean handlePrecedenceAnnotation(RuntimeAnnotations runtimeAnnotations, AjAttributeStruct struct) {
+ Annotation aspect = getAnnotation(runtimeAnnotations, AjcMemberMaker.DECLAREPRECEDENCE_ANNOTATION);
+ if (aspect != null) {
+ ElementNameValuePair precedence = getAnnotationElement(aspect, VALUE);
+ if (precedence != null) {
+ String precedencePattern = precedence.getValue().stringifyValue();
+ PatternParser parser = new PatternParser(precedencePattern);
+ DeclarePrecedence ajPrecedence = parser.parseDominates();
+ struct.ajAttributes.add(new AjAttribute.DeclareAttribute(ajPrecedence));
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Read @Before
+ *
+ * @param runtimeAnnotations
+ * @param struct
+ * @return true if found
+ */
+ private static boolean handleBeforeAnnotation(RuntimeAnnotations runtimeAnnotations, AjAttributeMethodStruct struct, ResolvedPointcutDefinition preResolvedPointcut) {
+ Annotation before = getAnnotation(runtimeAnnotations, AjcMemberMaker.BEFORE_ANNOTATION);
+ if (before != null) {
+ ElementNameValuePair beforeAdvice = getAnnotationElement(before, VALUE);
+ if (beforeAdvice != null) {
+ // this/target/args binding
+ FormalBinding[] bindings = new org.aspectj.weaver.patterns.FormalBinding[0];
+ try {
+ bindings = extractBindings(struct);
+ } catch (UnreadableDebugInfoException unreadableDebugInfoException) {
+ return false;
+ }
+ IScope binding = new BindingScope(
+ struct.enclosingType,
+ bindings
+ );
+
+ // joinpoint, staticJoinpoint binding
+ int extraArgument = extractExtraArgument(struct.method);
+
+ Pointcut pc = null;
+ if (preResolvedPointcut != null) {
+ pc = preResolvedPointcut.getPointcut();
+ } else {
+ pc = parsePointcut(beforeAdvice.getValue().stringifyValue(), struct);
+ if (pc == null) return false;//parse error
+ pc.resolve(binding);
+ }
+ setIgnoreUnboundBindingNames(pc, bindings);
+
+ struct.ajAttributes.add(
+ new AjAttribute.AdviceAttribute(
+ AdviceKind.Before,
+ pc,
+ extraArgument,
+ -1,
+ -1,
+ struct.context
+ )
+ );
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Read @After
+ *
+ * @param runtimeAnnotations
+ * @param struct
+ * @return true if found
+ */
+ private static boolean handleAfterAnnotation(RuntimeAnnotations runtimeAnnotations, AjAttributeMethodStruct struct, ResolvedPointcutDefinition preResolvedPointcut) {
+ Annotation after = getAnnotation(runtimeAnnotations, AjcMemberMaker.AFTER_ANNOTATION);
+ if (after != null) {
+ ElementNameValuePair afterAdvice = getAnnotationElement(after, VALUE);
+ if (afterAdvice != null) {
+ // this/target/args binding
+ FormalBinding[] bindings = new org.aspectj.weaver.patterns.FormalBinding[0];
+ try {
+ bindings = extractBindings(struct);
+ } catch (UnreadableDebugInfoException unreadableDebugInfoException) {
+ return false;
+ }
+ IScope binding = new BindingScope(
+ struct.enclosingType,
+ bindings
+ );
+
+ // joinpoint, staticJoinpoint binding
+ int extraArgument = extractExtraArgument(struct.method);
+
+ Pointcut pc = null;
+ if (preResolvedPointcut != null) {
+ pc = preResolvedPointcut.getPointcut();
+ } else {
+ pc = parsePointcut(afterAdvice.getValue().stringifyValue(), struct);
+ if (pc == null) return false;//parse error
+ pc.resolve(binding);
+ }
+ setIgnoreUnboundBindingNames(pc, bindings);
+
+ struct.ajAttributes.add(
+ new AjAttribute.AdviceAttribute(
+ AdviceKind.After,
+ pc,
+ extraArgument,
+ -1,
+ -1,
+ struct.context
+ )
+ );
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Read @AfterReturning
+ *
+ * @param runtimeAnnotations
+ * @param struct
+ * @return true if found
+ */
+ private static boolean handleAfterReturningAnnotation(RuntimeAnnotations runtimeAnnotations, AjAttributeMethodStruct struct, ResolvedPointcutDefinition preResolvedPointcut) {
+ Annotation after = getAnnotation(runtimeAnnotations, AjcMemberMaker.AFTERRETURNING_ANNOTATION);
+ if (after != null) {
+ ElementNameValuePair annValue = getAnnotationElement(after, VALUE);
+ ElementNameValuePair annPointcut = getAnnotationElement(after, POINTCUT);
+ ElementNameValuePair annReturned = getAnnotationElement(after, RETURNING);
+
+ // extract the pointcut and returned type/binding - do some checks
+ String pointcut = null;
+ String returned = null;
+ if ((annValue != null && annPointcut != null) || (annValue == null && annPointcut == null)) {
+ reportError("@AfterReturning: either 'value' or 'poincut' must be provided, not both", struct);
+ return false;
+ }
+ if (annValue != null) {
+ pointcut = annValue.getValue().stringifyValue();
+ } else {
+ pointcut = annPointcut.getValue().stringifyValue();
+ }
+ if (isNullOrEmpty(pointcut)) {
+ reportError("@AfterReturning: either 'value' or 'poincut' must be provided, not both", struct);
+ return false;
+ }
+ if (annReturned != null) {
+ returned = annReturned.getValue().stringifyValue();
+ if (isNullOrEmpty(returned))
+ returned = null;
+ }
+
+ // this/target/args binding
+ // exclude the return binding from the pointcut binding since it is an extraArg binding
+ FormalBinding[] bindings = new org.aspectj.weaver.patterns.FormalBinding[0];
+ try {
+ bindings = (returned == null ? extractBindings(struct) : extractBindings(struct, returned));
+ } catch (UnreadableDebugInfoException unreadableDebugInfoException) {
+ return false;
+ }
+ IScope binding = new BindingScope(
+ struct.enclosingType,
+ bindings
+ );
+
+ // joinpoint, staticJoinpoint binding
+ int extraArgument = extractExtraArgument(struct.method);
+
+ // return binding
+ if (returned != null) {
+ extraArgument |= Advice.ExtraArgument;
+ }
+
+ Pointcut pc = null;
+ if (preResolvedPointcut != null) {
+ pc = preResolvedPointcut.getPointcut();
+ } else {
+ pc = parsePointcut(pointcut, struct);
+ if (pc == null) return false;//parse error
+ pc.resolve(binding);
+ }
+ setIgnoreUnboundBindingNames(pc, bindings);
+
+ struct.ajAttributes.add(
+ new AjAttribute.AdviceAttribute(
+ AdviceKind.AfterReturning,
+ pc,
+ extraArgument,
+ -1,
+ -1,
+ struct.context
+ )
+ );
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Read @AfterThrowing
+ *
+ * @param runtimeAnnotations
+ * @param struct
+ * @return true if found
+ */
+ private static boolean handleAfterThrowingAnnotation(RuntimeAnnotations runtimeAnnotations, AjAttributeMethodStruct struct, ResolvedPointcutDefinition preResolvedPointcut) {
+ Annotation after = getAnnotation(runtimeAnnotations, AjcMemberMaker.AFTERTHROWING_ANNOTATION);
+ if (after != null) {
+ ElementNameValuePair annValue = getAnnotationElement(after, VALUE);
+ ElementNameValuePair annPointcut = getAnnotationElement(after, POINTCUT);
+ ElementNameValuePair annThrowned = getAnnotationElement(after, THROWING);
+
+ // extract the pointcut and throwned type/binding - do some checks
+ String pointcut = null;
+ String throwned = null;
+ if ((annValue != null && annPointcut != null) || (annValue == null && annPointcut == null)) {
+ reportError("@AfterThrowing: either 'value' or 'poincut' must be provided, not both", struct);
+ return false;
+ }
+ if (annValue != null) {
+ pointcut = annValue.getValue().stringifyValue();
+ } else {
+ pointcut = annPointcut.getValue().stringifyValue();
+ }
+ if (isNullOrEmpty(pointcut)) {
+ reportError("@AfterThrowing: either 'value' or 'poincut' must be provided, not both", struct);
+ return false;
+ }
+ if (annThrowned != null) {
+ throwned = annThrowned.getValue().stringifyValue();
+ if (isNullOrEmpty(throwned))
+ throwned = null;
+ }
+
+ // this/target/args binding
+ // exclude the throwned binding from the pointcut binding since it is an extraArg binding
+ FormalBinding[] bindings = new org.aspectj.weaver.patterns.FormalBinding[0];
+ try {
+ bindings = (throwned == null ? extractBindings(struct) : extractBindings(struct, throwned));
+ } catch (UnreadableDebugInfoException unreadableDebugInfoException) {
+ return false;
+ }
+ IScope binding = new BindingScope(
+ struct.enclosingType,
+ bindings
+ );
+
+ // joinpoint, staticJoinpoint binding
+ int extraArgument = extractExtraArgument(struct.method);
+
+ // return binding
+ if (throwned != null) {
+ extraArgument |= Advice.ExtraArgument;
+ }
+
+ Pointcut pc = null;
+ if (preResolvedPointcut != null) {
+ pc = preResolvedPointcut.getPointcut();
+ } else {
+ pc = parsePointcut(pointcut, struct);
+ if (pc == null) return false;//parse error
+ pc.resolve(binding);
+ }
+ setIgnoreUnboundBindingNames(pc, bindings);
+
+ struct.ajAttributes.add(
+ new AjAttribute.AdviceAttribute(
+ AdviceKind.AfterThrowing,
+ pc,
+ extraArgument,
+ -1,
+ -1,
+ struct.context
+ )
+ );
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Read @Around
+ *
+ * @param runtimeAnnotations
+ * @param struct
+ * @return true if found
+ */
+ private static boolean handleAroundAnnotation(RuntimeAnnotations runtimeAnnotations, AjAttributeMethodStruct struct, ResolvedPointcutDefinition preResolvedPointcut) {
+ Annotation around = getAnnotation(runtimeAnnotations, AjcMemberMaker.AROUND_ANNOTATION);
+ if (around != null) {
+ ElementNameValuePair aroundAdvice = getAnnotationElement(around, VALUE);
+ if (aroundAdvice != null) {
+ // this/target/args binding
+ FormalBinding[] bindings = new org.aspectj.weaver.patterns.FormalBinding[0];
+ try {
+ bindings = extractBindings(struct);
+ } catch (UnreadableDebugInfoException unreadableDebugInfoException) {
+ return false;
+ }
+ IScope binding = new BindingScope(
+ struct.enclosingType,
+ bindings
+ );
+
+ // joinpoint, staticJoinpoint binding
+ int extraArgument = extractExtraArgument(struct.method);
+
+ Pointcut pc = null;
+ if (preResolvedPointcut != null) {
+ pc = preResolvedPointcut.getPointcut();
+ } else {
+ pc = parsePointcut(aroundAdvice.getValue().stringifyValue(), struct);
+ if (pc == null) return false;//parse error
+ pc.resolve(binding);
+ }
+ setIgnoreUnboundBindingNames(pc, bindings);
+
+ struct.ajAttributes.add(
+ new AjAttribute.AdviceAttribute(
+ AdviceKind.Around,
+ pc,
+ extraArgument,
+ -1,
+ -1,
+ struct.context
+ )
+ );
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Read @Pointcut and handle the resolving in a lazy way to deal with pointcut references
+ *
+ * @param runtimeAnnotations
+ * @param struct
+ */
+ private static void handlePointcutAnnotation(RuntimeAnnotations runtimeAnnotations, AjAttributeMethodStruct struct) {
+ Annotation pointcut = getAnnotation(runtimeAnnotations, AjcMemberMaker.POINTCUT_ANNOTATION);
+ if (pointcut != null) {
+ ElementNameValuePair pointcutExpr = getAnnotationElement(pointcut, VALUE);
+ if (pointcutExpr != null) {
+
+ // semantic check: the method must return void
+ if (!Type.VOID.equals(struct.method.getReturnType())) {
+ reportWarning("Found @Pointcut on a method not returning void", struct);
+ ;//no need to stop
+ }
+ // semantic check: the method must not throw anything
+ if (struct.method.getExceptionTable() != null) {
+ reportWarning("Found @Pointcut on a method throwing exception", struct);
+ ;// no need to stop
+ }
+
+ // this/target/args binding
+ final IScope binding;
+ try {
+ binding = new BindingScope(
+ struct.enclosingType,
+ extractBindings(struct)
+ );
+ } catch (UnreadableDebugInfoException e) {
+ return;
+ }
+
+ TypeX[] argumentTypes = new TypeX[struct.method.getArgumentTypes().length];
+ for (int i = 0; i < argumentTypes.length; i++) {
+ argumentTypes[i] = TypeX.forSignature(struct.method.getArgumentTypes()[i].getSignature());
+ }
+
+ // use a LazyResolvedPointcutDefinition so that the pointcut is resolved lazily
+ // since for it to be resolved, we will need other pointcuts to be registered as well
+ Pointcut pc = parsePointcut(pointcutExpr.getValue().stringifyValue(), struct);
+ if (pc == null) return;//parse error
+ // do not resolve binding now but lazily
+ pc.setLocation(struct.context, -1, -1);
+ struct.ajAttributes.add(
+ new AjAttribute.PointcutDeclarationAttribute(
+ new LazyResolvedPointcutDefinition(
+ struct.enclosingType,
+ struct.method.getModifiers(),
+ struct.method.getName(),
+ argumentTypes,
+ pc,
+ binding
+ )
+ )
+ );
+ }
+ }
+ }
+
+ /**
+ * Read @DeclareError, @DeclareWarning
+ *
+ * @param runtimeAnnotations
+ * @param struct
+ * @return true if found
+ */
+ private static boolean handleDeclareErrorOrWarningAnnotation(RuntimeAnnotations runtimeAnnotations, AjAttributeFieldStruct struct) {
+ Annotation error = getAnnotation(runtimeAnnotations, AjcMemberMaker.DECLAREERROR_ANNOTATION);
+ boolean hasError = false;
+ if (error != null) {
+ ElementNameValuePair declareError = getAnnotationElement(error, VALUE);
+ if (declareError != null) {
+ if (!STRING_DESC.equals(struct.field.getSignature()) || struct.field.getConstantValue() == null) {
+ reportError("@DeclareError used on a non String constant field", struct);
+ return false;
+ }
+ FormalBinding[] bindings = new org.aspectj.weaver.patterns.FormalBinding[0];
+ IScope binding = new BindingScope(
+ struct.enclosingType,
+ bindings
+ );
+ Pointcut pc = parsePointcut(declareError.getValue().stringifyValue(), struct);
+ if (pc == null) {
+ hasError = false;//cannot parse pointcut
+ } else {
+ pc .resolve(binding);
+ DeclareErrorOrWarning deow = new DeclareErrorOrWarning(true, pc, struct.field.getConstantValue().toString());
+ deow.setLocation(struct.context, -1, -1);
+ struct.ajAttributes.add(new AjAttribute.DeclareAttribute(deow));
+ hasError = true;
+ }
+ }
+ }
+ Annotation warning = getAnnotation(runtimeAnnotations, AjcMemberMaker.DECLAREWARNING_ANNOTATION);
+ boolean hasWarning = false;
+ if (warning != null) {
+ ElementNameValuePair declareWarning = getAnnotationElement(warning, VALUE);
+ if (declareWarning != null) {
+ if (!STRING_DESC.equals(struct.field.getSignature()) || struct.field.getConstantValue() == null) {
+ reportError("@DeclareWarning used on a non String constant field", struct);
+ return false;
+ }
+ FormalBinding[] bindings = new org.aspectj.weaver.patterns.FormalBinding[0];
+ IScope binding = new BindingScope(
+ struct.enclosingType,
+ bindings
+ );
+ Pointcut pc = parsePointcut(declareWarning.getValue().stringifyValue(), struct);
+ if (pc == null) {
+ hasWarning = false;//cannot parse pointcut
+ } else {
+ pc.resolve(binding);
+ DeclareErrorOrWarning deow = new DeclareErrorOrWarning(false, pc, struct.field.getConstantValue().toString());
+ deow.setLocation(struct.context, -1, -1);
+ struct.ajAttributes.add(new AjAttribute.DeclareAttribute(deow));
+ return hasWarning = true;
+ }
+ }
+ }
+ return hasError || hasWarning;
+ }
+
+ /**
+ * Returns a readable representation of a method.
+ * Method.toString() is not suitable.
+ *
+ * @param method
+ * @return
+ */
+ private static String methodToString(Method method) {
+ StringBuffer sb = new StringBuffer();
+ sb.append(method.getName());
+ sb.append(method.getSignature());
+ return sb.toString();
+ }
+
+ /**
+ * Returns a readable representation of a field.
+ * Field.toString() is not suitable.
+ *
+ * @param field
+ * @return
+ */
+ private static String fieldToString(Field field) {
+ StringBuffer sb = new StringBuffer();
+ sb.append(field.getName()).append(' ');
+ sb.append(field.getSignature());
+ return sb.toString();
+ }
+
+ /**
+ * Build the bindings for a given method (pointcut / advice)
+ *
+ * @param struct
+ * @return null if no debug info is available
+ */
+ private static FormalBinding[] extractBindings(AjAttributeMethodStruct struct)
+ throws UnreadableDebugInfoException {
+ Method method = struct.method;
+ String[] argumentNames = struct.getArgumentNames();
+
+ // assert debug info was here
+ if (argumentNames.length != method.getArgumentTypes().length) {
+ reportError("Cannot read debug info for @Aspect to handle formal binding in pointcuts (please compile with 'javac -g' or '<javac debug='true'.../>' in Ant)", struct);
+ throw new UnreadableDebugInfoException();
+ }
+
+ List bindings = new ArrayList();
+ for (int i = 0; i < argumentNames.length; i++) {
+ String argumentName = argumentNames[i];
+ TypeX argumentType = TypeX.forSignature(method.getArgumentTypes()[i].getSignature());
+
+ // do not bind JoinPoint / StaticJoinPoint / EnclosingStaticJoinPoint
+ // TODO solve me : this means that the JP/SJP/ESJP cannot appear as binding
+ // f.e. when applying advice on advice etc
+ if ((AjcMemberMaker.TYPEX_JOINPOINT.equals(argumentType)
+ || AjcMemberMaker.TYPEX_PROCEEDINGJOINPOINT.equals(argumentType)
+ || AjcMemberMaker.TYPEX_STATICJOINPOINT.equals(argumentType)
+ || AjcMemberMaker.TYPEX_ENCLOSINGSTATICJOINPOINT.equals(argumentType)
+ || AjcMemberMaker.AROUND_CLOSURE_TYPE.equals(argumentType))) {
+ //continue;// skip
+ bindings.add(new FormalBinding.ImplicitFormalBinding(argumentType, argumentName, i));
+ } else {
+ bindings.add(new FormalBinding(argumentType, argumentName, i));
+ }
+ }
+
+ return (FormalBinding[]) bindings.toArray(new FormalBinding[]{});
+ }
+
+ //FIXME alex deal with exclude index
+ private static FormalBinding[] extractBindings(AjAttributeMethodStruct struct, String excludeFormal)
+ throws UnreadableDebugInfoException {
+ FormalBinding[] bindings = extractBindings(struct);
+ int excludeIndex = -1;
+ for (int i = 0; i < bindings.length; i++) {
+ FormalBinding binding = bindings[i];
+ if (binding.getName().equals(excludeFormal)) {
+ excludeIndex = i;
+ bindings[i] = new FormalBinding.ImplicitFormalBinding(
+ binding.getType(), binding.getName(), binding.getIndex()
+ );
+ break;
+ }
+ }
+ return bindings;
+//
+// if (excludeIndex >= 0) {
+// FormalBinding[] bindingsFiltered = new FormalBinding[bindings.length-1];
+// int k = 0;
+// for (int i = 0; i < bindings.length; i++) {
+// if (i == excludeIndex) {
+// ;
+// } else {
+// bindingsFiltered[k] = new FormalBinding(bindings[i].getType(), bindings[i].getName(), k);
+// k++;
+// }
+// }
+// return bindingsFiltered;
+// } else {
+// return bindings;
+// }
+ }
+
+
+ /**
+ * Compute the flag for the xxxJoinPoint extra argument
+ *
+ * @param method
+ * @return
+ */
+ private static int extractExtraArgument(Method method) {
+ int extraArgument = 0;
+ Type[] methodArgs = method.getArgumentTypes();
+ for (int i = 0; i < methodArgs.length; i++) {
+ String methodArg = methodArgs[i].getSignature();
+ if (AjcMemberMaker.TYPEX_JOINPOINT.getSignature().equals(methodArg)) {
+ extraArgument |= Advice.ThisJoinPoint;
+ } else if (AjcMemberMaker.TYPEX_PROCEEDINGJOINPOINT.getSignature().equals(methodArg)) {
+ extraArgument |= Advice.ThisJoinPoint;
+ } else if (AjcMemberMaker.TYPEX_STATICJOINPOINT.getSignature().equals(methodArg)) {
+ extraArgument |= Advice.ThisJoinPointStaticPart;
+ } else if (AjcMemberMaker.TYPEX_ENCLOSINGSTATICJOINPOINT.getSignature().equals(methodArg)) {
+ extraArgument |= Advice.ThisEnclosingJoinPointStaticPart;
+ }
+ }
+ return extraArgument;
+ }
+
+ /**
+ * Returns the runtime (RV/RIV) annotation of type annotationType or null if no such annotation
+ *
+ * @param rvs
+ * @param annotationType
+ * @return
+ */
+ private static Annotation getAnnotation(RuntimeAnnotations rvs, TypeX annotationType) {
+ final String annotationTypeName = annotationType.getName();
+ for (Iterator iterator = rvs.getAnnotations().iterator(); iterator.hasNext();) {
+ Annotation rv = (Annotation) iterator.next();
+ if (annotationTypeName.equals(rv.getTypeName())) {
+ return rv;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Returns the value of a given element of an annotation or null if not found
+ * Caution: Does not handles default value.
+ *
+ * @param annotation
+ * @param elementName
+ * @return
+ */
+ private static ElementNameValuePair getAnnotationElement(Annotation annotation, String elementName) {
+ for (Iterator iterator1 = annotation.getValues().iterator(); iterator1.hasNext();) {
+ ElementNameValuePair element = (ElementNameValuePair) iterator1.next();
+ if (elementName.equals(element.getNameString())) {
+ return element;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Extract the method argument names as in source from debug info
+ * returns an empty array upon inconsistency
+ *
+ * @param method
+ * @return
+ */
+ private static String[] getMethodArgumentNamesAsInSource(Method method) {
+ if (method.getArgumentTypes().length == 0) {
+ return EMPTY_STRINGS;
+ }
+
+ final int startAtStackIndex = method.isStatic() ? 0 : 1;
+ final List arguments = new ArrayList();
+ LocalVariableTable lt = (LocalVariableTable) method.getLocalVariableTable();
+ if (lt != null) {
+ for (int j = 0; j < lt.getLocalVariableTable().length; j++) {
+ LocalVariable localVariable = lt.getLocalVariableTable()[j];
+ if (localVariable.getStartPC() == 0) {
+ if (localVariable.getIndex() >= startAtStackIndex) {
+ arguments.add(new MethodArgument(localVariable.getName(), localVariable.getIndex()));
+ }
+ }
+ }
+ }
+
+ if (arguments.size() != method.getArgumentTypes().length) {
+ return EMPTY_STRINGS;
+ }
+
+ // sort by index
+ Collections.sort(
+ arguments, new Comparator() {
+ public int compare(Object o, Object o1) {
+ MethodArgument mo = (MethodArgument) o;
+ MethodArgument mo1 = (MethodArgument) o1;
+ if (mo.indexOnStack == mo1.indexOnStack) {
+ return 0;
+ } else if (mo.indexOnStack > mo1.indexOnStack) {
+ return 1;
+ } else {
+ return -1;
+ }
+ }
+ }
+ );
+ String[] argumentNames = new String[arguments.size()];
+ int i = 0;
+ for (Iterator iterator = arguments.iterator(); iterator.hasNext(); i++) {
+ MethodArgument methodArgument = (MethodArgument) iterator.next();
+ argumentNames[i] = methodArgument.name;
+ }
+ return argumentNames;
+ }
+
+ /**
+ * A method argument, used for sorting by indexOnStack (ie order in signature)
+ *
+ * @author <a href="mailto:alex AT gnilux DOT com">Alexandre Vasseur</a>
+ */
+ private static class MethodArgument {
+ String name;
+ int indexOnStack;
+
+ public MethodArgument(String name, int indexOnStack) {
+ this.name = name;
+ this.indexOnStack = indexOnStack;
+ }
+ }
+
+ /**
+ * BindingScope that knows the enclosingType, which is needed for pointcut reference resolution
+ *
+ * @author <a href="mailto:alex AT gnilux DOT com">Alexandre Vasseur</a>
+ */
+ public static class BindingScope extends SimpleScope {
+ private ResolvedTypeX m_enclosingType;
+
+ public BindingScope(ResolvedTypeX type, FormalBinding[] bindings) {
+ super(type.getWorld(), bindings);
+ m_enclosingType = type;
+ }
+
+ public ResolvedTypeX getEnclosingType() {
+ return m_enclosingType;
+ }
+ }
+
+ /**
+ * LazyResolvedPointcutDefinition lazyly resolve the pointcut so that we have time to register all
+ * pointcut referenced before pointcut resolution happens
+ *
+ * @author <a href="mailto:alex AT gnilux DOT com">Alexandre Vasseur</a>
+ */
+ public static class LazyResolvedPointcutDefinition extends ResolvedPointcutDefinition {
+ private Pointcut m_pointcutUnresolved;
+ private IScope m_binding;
+
+ private Pointcut m_lazyPointcut = null;
+
+ public LazyResolvedPointcutDefinition(ResolvedTypeX declaringType, int modifiers, String name, TypeX[] parameterTypes,
+ Pointcut pointcut, IScope binding) {
+ super(declaringType, modifiers, name, parameterTypes, null);
+ m_pointcutUnresolved = pointcut;
+ m_binding = binding;
+ }
+
+ public Pointcut getPointcut() {
+ if (m_lazyPointcut == null) {
+ m_lazyPointcut = m_pointcutUnresolved.resolve(m_binding);
+ m_lazyPointcut.copyLocationFrom(m_pointcutUnresolved);
+ }
+ return m_lazyPointcut;
+ }
+ }
+
+ /**
+ * Helper to test empty strings
+ *
+ * @param s
+ * @return
+ */
+ private static boolean isNullOrEmpty(String s) {
+ return (s == null || s.length() <= 0);
+ }
+
+ /**
+ * Set the pointcut bindings for which to ignore unbound issues, so that we can implicitly bind
+ * xxxJoinPoint for @AJ advices
+ *
+ * @param pointcut
+ * @param bindings
+ */
+ private static void setIgnoreUnboundBindingNames(Pointcut pointcut, FormalBinding[] bindings) {
+ // register ImplicitBindings as to be ignored since unbound
+ // TODO is it likely to fail in a bad way if f.e. this(jp) etc ?
+ List ignores = new ArrayList();
+ for (int i = 0; i < bindings.length; i++) {
+ FormalBinding formalBinding = bindings[i];
+ if (formalBinding instanceof FormalBinding.ImplicitFormalBinding) {
+ ignores.add(formalBinding.getName());
+ }
+ }
+ pointcut.m_ignoreUnboundBindingForNames = (String[]) ignores.toArray(new String[ignores.size()]);
+ }
+
+ /**
+ * A check exception when we cannot read debug info (needed for formal binding)
+ */
+ private static class UnreadableDebugInfoException extends Exception {
+ }
+
+ /**
+ * Report an error
+ *
+ * @param message
+ * @param location
+ */
+ private static void reportError(String message, AjAttributeStruct location) {
+ if (!location.handler.isIgnoring(IMessage.ERROR)) {
+ location.handler.handleMessage(
+ new Message(
+ message,
+ location.enclosingType.getSourceLocation(),
+ true
+ )
+ );
+ }
+ }
+
+ /**
+ * Report a warning
+ *
+ * @param message
+ * @param location
+ */
+ private static void reportWarning(String message, AjAttributeStruct location) {
+ if (!location.handler.isIgnoring(IMessage.WARNING)) {
+ location.handler.handleMessage(
+ new Message(
+ message,
+ location.enclosingType.getSourceLocation(),
+ false
+ )
+ );
+ }
+ }
+
+ /**
+ * Parse the given pointcut, return null on failure and issue an error
+ *
+ * @param pointcutString
+ * @param location
+ * @return
+ */
+ private static Pointcut parsePointcut(String pointcutString, AjAttributeStruct location) {
+ try {
+ Pointcut pointcut = Pointcut.fromString(pointcutString);
+ pointcut.setLocation(location.context, -1, -1);//FIXME -1,-1 is not good enough
+ return pointcut;
+ } catch (ParserException e) {
+ reportError("Invalid pointcut '" + pointcutString + "' : " + e.getLocation(), location);
+ return null;
+ }
+ }
+
+ /**
+ * Parse the given type pattern, return null on failure and issue an error
+ *
+ * @param patternString
+ * @param location
+ * @return
+ */
+ private static TypePattern parseTypePattern(String patternString, AjAttributeStruct location) {
+ try {
+ TypePattern typePattern = new PatternParser(patternString).parseTypePattern();
+ typePattern.setLocation(location.context, -1, -1);//FIXME -1,-1 is not good enough
+ return typePattern;
+ } catch (ParserException e) {
+ reportError("Invalid type pattern'" + patternString + "' : " + e.getLocation(), location);
+ return null;
+ }
+ }
+}
import org.aspectj.weaver.WeaverMessages;
import org.aspectj.weaver.World;
import org.aspectj.weaver.PerObjectInterfaceTypeMunger;
-import org.aspectj.weaver.ataspectj.Ajc5MemberMaker;
import org.aspectj.weaver.ast.Literal;
import org.aspectj.weaver.ast.Test;
import org.aspectj.weaver.patterns.ExactTypePattern;
if (v == null) {
// if not @AJ aspect, go on with the regular binding handling
- if (!Ajc5MemberMaker.isAnnotationStyleAspect(getConcreteAspect())) {
+ if (!getConcreteAspect().isAnnotationStyleAspect()) {
continue;
} else {
// ATAJ: for @AJ aspects, handle implicit binding of xxJoinPoint
// ATAJ: for code style aspect, handles the extraFlag as usual ie not
// in the middle of the formal bindings but at the end, in a rock solid ordering
- if (!Ajc5MemberMaker.isAnnotationStyleAspect(getConcreteAspect())) {
+ if (!getConcreteAspect().isAnnotationStyleAspect()) {
if (getKind() == AdviceKind.Around) {
il.append(closureInstantiation);
} else if (hasExtraParameter()) {
import org.aspectj.weaver.ResolvedTypeX;
import org.aspectj.weaver.TypeX;
import org.aspectj.weaver.World;
-import org.aspectj.weaver.ataspectj.Aj5Attributes;
final class BcelField extends ResolvedMember {
private void unpackAttributes(World world) {
Attribute[] attrs = field.getAttributes();
List as = BcelAttributes.readAjAttributes(getDeclaringType().getClassName(),attrs, getSourceContext(world),world.getMessageHandler());
- as.addAll(Aj5Attributes.readAj5FieldAttributes(field, world.resolve(getDeclaringType()), getSourceContext(world), world.getMessageHandler()));
+ as.addAll(AtAjAttributes.readAj5FieldAttributes(field, world.resolve(getDeclaringType()), getSourceContext(world), world.getMessageHandler()));
for (Iterator iter = as.iterator(); iter.hasNext();) {
AjAttribute a = (AjAttribute) iter.next();
import org.aspectj.weaver.ShadowMunger;
import org.aspectj.weaver.TypeX;
import org.aspectj.weaver.World;
-import org.aspectj.weaver.ataspectj.Aj5Attributes;
final class BcelMethod extends ResolvedMember {
associatedShadowMunger = null;
List as = BcelAttributes.readAjAttributes(getDeclaringType().getClassName(),method.getAttributes(), getSourceContext(world),world.getMessageHandler());
processAttributes(world, as);
- as = Aj5Attributes.readAj5MethodAttributes(method, world.resolve(getDeclaringType()), preResolvedPointcut,getSourceContext(world), world.getMessageHandler());
+ as = AtAjAttributes.readAj5MethodAttributes(method, world.resolve(getDeclaringType()), preResolvedPointcut,getSourceContext(world), world.getMessageHandler());
processAttributes(world,as);
}
import org.aspectj.weaver.ResolvedTypeX;
import org.aspectj.weaver.TypeX;
import org.aspectj.weaver.WeaverStateInfo;
+import org.aspectj.weaver.AjcMemberMaker;
import org.aspectj.weaver.patterns.PerClause;
-import org.aspectj.weaver.ataspectj.Aj5Attributes;
-import org.aspectj.weaver.ataspectj.Ajc5MemberMaker;
// ??? exposed for testing
public boolean isAnnotationStyleAspect() {
if (!discoveredWhetherAnnotationStyle) {
discoveredWhetherAnnotationStyle = true;
- isAnnotationStyleAspect = !isCodeStyleAspect && hasAnnotation(Ajc5MemberMaker.ASPECT);
+ isAnnotationStyleAspect = !isCodeStyleAspect && hasAnnotation(AjcMemberMaker.ASPECT_ANNOTATION);
}
return isAnnotationStyleAspect;
}
// Pass in empty list that can store things for readAj5 to process
List l = BcelAttributes.readAjAttributes(javaClass.getClassName(),javaClass.getAttributes(), getResolvedTypeX().getSourceContext(),getResolvedTypeX().getWorld().getMessageHandler());
processAttributes(l,pointcuts,false);
- l = Aj5Attributes.readAj5ClassAttributes(javaClass, getResolvedTypeX(), getResolvedTypeX().getSourceContext(), getResolvedTypeX().getWorld().getMessageHandler(),isCodeStyleAspect);
+ l = AtAjAttributes.readAj5ClassAttributes(javaClass, getResolvedTypeX(), getResolvedTypeX().getSourceContext(), getResolvedTypeX().getWorld().getMessageHandler(),isCodeStyleAspect);
processAttributes(l,pointcuts,true);
this.pointcuts = (ResolvedPointcutDefinition[])
import org.aspectj.weaver.WeaverMessages;
import org.aspectj.weaver.World;
import org.aspectj.weaver.ast.Var;
-import org.aspectj.weaver.ataspectj.Ajc5MemberMaker;
/*
}
// ATAJ for @AJ aspect we need to link the closure with the joinpoint instance
- if (Ajc5MemberMaker.isAnnotationStyleAspect(munger.getConcreteAspect())) {
- //advice.append(new POP());
+ if (munger.getConcreteAspect().isAnnotationStyleAspect()) {
closureInstantiation.append(Utility.createInvoke(
getFactory(),
getWorld(),
)
));
}
- //System.err.println(closureInstantiation);
-
InstructionList advice = new InstructionList();
advice.append(munger.getAdviceArgSetup(this, null, closureInstantiation));
-// advice.append(closureInstantiation);
// invoke the advice
advice.append(munger.getNonTestAdviceInstructions(this));
import org.aspectj.weaver.VersionedDataInputStream;
import org.aspectj.weaver.World;
import org.aspectj.weaver.bcel.BcelAccessForInlineMunger;
-import org.aspectj.weaver.ataspectj.Ajc5MemberMaker;
import org.aspectj.weaver.ast.Expr;
import org.aspectj.weaver.ast.Test;
}
//ATAJ inline around advice support - don't use a late munger to allow around inling for itself
- if (Ajc5MemberMaker.isAnnotationStyleAspect(inAspect)) {
+ if (inAspect.isAnnotationStyleAspect()) {
inAspect.crosscuttingMembers.addTypeMunger(new BcelAccessForInlineMunger(inAspect));
}
import org.aspectj.weaver.VersionedDataInputStream;
import org.aspectj.weaver.World;
import org.aspectj.weaver.bcel.BcelAccessForInlineMunger;
-import org.aspectj.weaver.ataspectj.Ajc5MemberMaker;
import org.aspectj.weaver.ast.Expr;
import org.aspectj.weaver.ast.Test;
import org.aspectj.weaver.ast.Var;
}
//ATAJ inline around advice support - don't use a late munger to allow around inling for itself
- if (Ajc5MemberMaker.isAnnotationStyleAspect(inAspect)) {
+ if (inAspect.isAnnotationStyleAspect()) {
inAspect.crosscuttingMembers.addTypeMunger(new BcelAccessForInlineMunger(inAspect));
}
import org.aspectj.weaver.ast.Expr;
import org.aspectj.weaver.ast.Literal;
import org.aspectj.weaver.ast.Test;
-import org.aspectj.weaver.ataspectj.Ajc5MemberMaker;
public class PerSingleton extends PerClause {
public PerSingleton() {
ret.inAspect = inAspect;
//ATAJ: add a munger to add the aspectOf(..) to the @AJ aspects
- if (!inAspect.isAbstract() && Ajc5MemberMaker.isAnnotationStyleAspect(inAspect)) {
+ if (!inAspect.isAbstract() && inAspect.isAnnotationStyleAspect()) {
//TODO will those change be ok if we add a serializable aspect ?
// dig: "can't be Serializable/Cloneable unless -XserializableAspects"
inAspect.crosscuttingMembers.addLateTypeMunger(
}
//ATAJ inline around advice support
- if (Ajc5MemberMaker.isAnnotationStyleAspect(inAspect)) {
+ if (inAspect.isAnnotationStyleAspect()) {
inAspect.crosscuttingMembers.addTypeMunger(new BcelAccessForInlineMunger(inAspect));
}
import org.aspectj.weaver.VersionedDataInputStream;
import org.aspectj.weaver.World;
import org.aspectj.weaver.bcel.BcelAccessForInlineMunger;
-import org.aspectj.weaver.ataspectj.Ajc5MemberMaker;
import org.aspectj.weaver.ast.Expr;
import org.aspectj.weaver.ast.Literal;
import org.aspectj.weaver.ast.Test;
}
//ATAJ inline around advice support - don't use a late munger to allow around inling for itself
- if (Ajc5MemberMaker.isAnnotationStyleAspect(inAspect)) {
+ if (inAspect.isAnnotationStyleAspect()) {
inAspect.crosscuttingMembers.addTypeMunger(new BcelAccessForInlineMunger(inAspect));
}
import org.aspectj.weaver.IClassFileProvider;
import org.aspectj.weaver.IWeaveRequestor;
import org.aspectj.weaver.ResolvedTypeX;
-import org.aspectj.weaver.ataspectj.Ajc5MemberMaker;
import org.aspectj.weaver.bcel.BcelWeaver;
import org.aspectj.weaver.bcel.BcelWorld;
import org.aspectj.weaver.bcel.UnwovenClassFile;
*/
private boolean shouldWeaveAspect (String name) {
ResolvedTypeX type = bcelWorld.resolve(name);
- return (type == null || !type.isAspect() || Ajc5MemberMaker.isAnnotationStyleAspect(type));
+ return (type == null || !type.isAspect() || type.isAnnotationStyleAspect());
}
/**