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
/******************************************************************************* * 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 java.io.ByteArrayInputStream; import java.io.IOException; import java.lang.reflect.Modifier; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.Comparator; import java.util.Iterator; import java.util.List; import java.util.StringTokenizer; import org.aspectj.apache.bcel.Constants; import org.aspectj.apache.bcel.classfile.Attribute; import org.aspectj.apache.bcel.classfile.Constant; import org.aspectj.apache.bcel.classfile.ConstantUtf8; 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.Unknown; import org.aspectj.apache.bcel.classfile.annotation.AnnotationGen; import org.aspectj.apache.bcel.classfile.annotation.ArrayElementValue; import org.aspectj.apache.bcel.classfile.annotation.ClassElementValue; import org.aspectj.apache.bcel.classfile.annotation.ElementValue; import org.aspectj.apache.bcel.classfile.annotation.NameValuePair; import org.aspectj.apache.bcel.classfile.annotation.RuntimeAnnos; import org.aspectj.apache.bcel.classfile.annotation.RuntimeVisAnnos; import org.aspectj.apache.bcel.generic.Type; import org.aspectj.asm.AsmManager; import org.aspectj.asm.IHierarchy; import org.aspectj.asm.IProgramElement; import org.aspectj.bridge.IMessage; import org.aspectj.bridge.IMessageHandler; import org.aspectj.bridge.ISourceLocation; import org.aspectj.bridge.Message; import org.aspectj.bridge.MessageUtil; import org.aspectj.weaver.Advice; import org.aspectj.weaver.AdviceKind; import org.aspectj.weaver.AjAttribute; import org.aspectj.weaver.AjAttribute.WeaverVersionInfo; import org.aspectj.weaver.AjcMemberMaker; import org.aspectj.weaver.BindingScope; import org.aspectj.weaver.ISourceContext; import org.aspectj.weaver.MethodDelegateTypeMunger; import org.aspectj.weaver.NameMangler; import org.aspectj.weaver.ReferenceType; import org.aspectj.weaver.ReferenceTypeDelegate; import org.aspectj.weaver.ResolvedMember; import org.aspectj.weaver.ResolvedPointcutDefinition; import org.aspectj.weaver.ResolvedType; import org.aspectj.weaver.UnresolvedType; import org.aspectj.weaver.VersionedDataInputStream; import org.aspectj.weaver.WeaverMessages; import org.aspectj.weaver.World; import org.aspectj.weaver.patterns.DeclareErrorOrWarning; import org.aspectj.weaver.patterns.DeclareParents; import org.aspectj.weaver.patterns.DeclareParentsMixin; 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.PerFromSuper; 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.TypePattern;
Annotation defined aspect reader. Reads the Java 5 annotations and turns them into AjAttributes
Author:Alexandre Vasseur
/** * Annotation defined aspect reader. 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<AjAttribute> NO_ATTRIBUTES = Collections.emptyList(); private final static String[] EMPTY_STRINGS = new String[0]; private final static String VALUE = "value"; private final static String ARGNAMES = "argNames"; 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;"; private final static String ASPECTJ_ANNOTATION_PACKAGE = "org.aspectj.lang.annotation"; private final static char PACKAGE_INITIAL_CHAR = ASPECTJ_ANNOTATION_PACKAGE.charAt(0);
A struct that allows to add extra arguments without always breaking the API
/** * A struct that allows to add extra arguments without always breaking the API */
private static class AjAttributeStruct {
The list of AjAttribute.XXX that we are populating from the @AJ read
/** * The list of AjAttribute.XXX that we are populating from the @AJ read */
List<AjAttribute> ajAttributes = new ArrayList<AjAttribute>();
The resolved type (class) for which we are reading @AJ for (be it class, method, field annotations)
/** * The resolved type (class) for which we are reading @AJ for (be it class, method, field annotations) */
final ResolvedType enclosingType; final ISourceContext context; final IMessageHandler handler; public AjAttributeStruct(ResolvedType type, ISourceContext sourceContext, IMessageHandler messageHandler) { enclosingType = type; context = sourceContext; handler = messageHandler; } }
A struct when we read @AJ on method
Author:Alexandre Vasseur
/** * 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 used for formal binding private String[] m_argumentNamesLazy = null; public String unparsedArgumentNames = null; // Set only if discovered as // argNames attribute of // annotation final Method method; final BcelMethod bMethod; public AjAttributeMethodStruct(Method method, BcelMethod bMethod, ResolvedType type, ISourceContext sourceContext, IMessageHandler messageHandler) { super(type, sourceContext, messageHandler); this.method = method; this.bMethod = bMethod; } public String[] getArgumentNames() { if (m_argumentNamesLazy == null) { m_argumentNamesLazy = getMethodArgumentNames(method, unparsedArgumentNames, this); } return m_argumentNamesLazy; } }
A struct when we read @AJ on field
/** * A struct when we read @AJ on field */
private static class AjAttributeFieldStruct extends AjAttributeStruct { final Field field; // final BcelField bField; public AjAttributeFieldStruct(Field field, BcelField bField, ResolvedType type, ISourceContext sourceContext, IMessageHandler messageHandler) { super(type, sourceContext, messageHandler); this.field = field; // this.bField = bField; } }
Annotations are RuntimeVisible only. This allow us to not visit RuntimeInvisible ones.
Params:
  • attribute –
Returns:true if runtime visible annotation
/** * Annotations are RuntimeVisible only. This allow us to not visit RuntimeInvisible ones. * * @param attribute * @return true if runtime visible annotation */
public static boolean acceptAttribute(Attribute attribute) { return (attribute instanceof RuntimeVisAnnos); }
Extract class level annotations and turn them into AjAttributes.
Params:
  • javaClass –
  • type –
  • context –
  • msgHandler –
Returns:list of AjAttributes
/** * Extract class level annotations and turn them into AjAttributes. * * @param javaClass * @param type * @param context * @param msgHandler * @return list of AjAttributes */
public static List<AjAttribute> readAj5ClassAttributes(AsmManager model, JavaClass javaClass, ReferenceType type, ISourceContext context, IMessageHandler msgHandler, boolean isCodeStyleAspect) { boolean ignoreThisClass = javaClass.getClassName().charAt(0) == PACKAGE_INITIAL_CHAR && javaClass.getClassName().startsWith(ASPECTJ_ANNOTATION_PACKAGE); if (ignoreThisClass) { return NO_ATTRIBUTES; } boolean containsPointcut = false; boolean containsAnnotationClassReference = false; Constant[] cpool = javaClass.getConstantPool().getConstantPool(); for (int i = 0; i < cpool.length; i++) { Constant constant = cpool[i]; if (constant != null && constant.getTag() == Constants.CONSTANT_Utf8) { String constantValue = ((ConstantUtf8) constant).getValue(); if (constantValue.length() > 28 && constantValue.charAt(1) == PACKAGE_INITIAL_CHAR) { if (constantValue.startsWith("Lorg/aspectj/lang/annotation")) { containsAnnotationClassReference = true; if ("Lorg/aspectj/lang/annotation/DeclareAnnotation;".equals(constantValue)) { msgHandler.handleMessage(new Message( "Found @DeclareAnnotation while current release does not support it (see '" + type.getName() + "')", IMessage.WARNING, null, type.getSourceLocation())); } if ("Lorg/aspectj/lang/annotation/Pointcut;".equals(constantValue)) { containsPointcut = true; } } } } } if (!containsAnnotationClassReference) { return NO_ATTRIBUTES; } AjAttributeStruct struct = new AjAttributeStruct(type, context, msgHandler); Attribute[] attributes = javaClass.getAttributes(); boolean hasAtAspectAnnotation = false; boolean hasAtPrecedenceAnnotation = false; WeaverVersionInfo wvinfo = null; for (int i = 0; i < attributes.length; i++) { Attribute attribute = attributes[i]; if (acceptAttribute(attribute)) { RuntimeAnnos rvs = (RuntimeAnnos) attribute; // we don't need to look for several attribute occurrences since // it cannot happen as per JSR175 if (!isCodeStyleAspect && !javaClass.isInterface()) { hasAtAspectAnnotation = handleAspectAnnotation(rvs, struct); // TODO AV - if put outside the if isCodeStyleAspect then we // would enable mix style hasAtPrecedenceAnnotation = handlePrecedenceAnnotation(rvs, struct); } // there can only be one RuntimeVisible bytecode attribute break; } } for (int i = attributes.length - 1; i >= 0; i--) { Attribute attribute = attributes[i]; if (attribute.getName().equals(WeaverVersionInfo.AttributeName)) { try { VersionedDataInputStream s = new VersionedDataInputStream(new ByteArrayInputStream( ((Unknown) attribute).getBytes()), null); wvinfo = WeaverVersionInfo.read(s); struct.ajAttributes.add(0, wvinfo); } catch (IOException ioe) { ioe.printStackTrace(); } } } if (wvinfo == null) { // If we are in here due to a resetState() call (presumably because of reweavable state processing), the // original type delegate will have been set with a version but that version will be missing from // the new set of attributes (looks like a bug where the version attribute was not included in the // data compressed into the attribute). So rather than 'defaulting' to current, we should use one // if it set on the delegate for the type. ReferenceTypeDelegate delegate = type.getDelegate(); if (delegate instanceof BcelObjectType) { wvinfo = ((BcelObjectType) delegate).getWeaverVersionAttribute(); if (wvinfo != null) { if (wvinfo.getMajorVersion() != WeaverVersionInfo.WEAVER_VERSION_MAJOR_UNKNOWN) { // use this one struct.ajAttributes.add(0, wvinfo); } else { wvinfo = null; } } } if (wvinfo == null) { struct.ajAttributes.add(0, wvinfo = new AjAttribute.WeaverVersionInfo()); } } // basic semantic check 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 NO_ATTRIBUTES; } // the following block will not detect @Pointcut in non @Aspect types // for optimization purpose if (!(hasAtAspectAnnotation || isCodeStyleAspect) && !containsPointcut) { return NO_ATTRIBUTES; } // FIXME AV - turn on when ajcMightHaveAspect // 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; // } // semantic check: @Aspect must be public // FIXME AV - do we really want to enforce that? // if (hasAtAspectAnnotation && !javaClass.isPublic()) { // msgHandler.handleMessage( // new Message( // "Found @Aspect annotation on a non public class '" + // javaClass.getClassName() + "'", // IMessage.ERROR, // null, // type.getSourceLocation() // ) // ); // 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 // we don't need to look in super class, the pointcut reference in the // grammar will do it 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 = null; boolean processedPointcut = false; Attribute[] mattributes = method.getAttributes(); for (int j = 0; j < mattributes.length; j++) { Attribute mattribute = mattributes[j]; if (acceptAttribute(mattribute)) { // TODO speed all this nonsense up rather than looking // through all the annotations every time // same for fields mstruct = new AjAttributeMethodStruct(method, null, type, context, msgHandler); processedPointcut = handlePointcutAnnotation((RuntimeAnnos) mattribute, mstruct); if (!processedPointcut) { processedPointcut = handleDeclareMixinAnnotation((RuntimeAnnos) mattribute, mstruct); } // there can only be one RuntimeVisible bytecode attribute break; } } if (processedPointcut) { struct.ajAttributes.addAll(mstruct.ajAttributes); } } // code style declare error / warning / implements / parents are field // attributes Field[] fs = javaClass.getFields(); for (int i = 0; i < fs.length; i++) { Field field = fs[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, null, type, context, msgHandler); Attribute[] fattributes = field.getAttributes(); for (int j = 0; j < fattributes.length; j++) { Attribute fattribute = fattributes[j]; if (acceptAttribute(fattribute)) { RuntimeAnnos frvs = (RuntimeAnnos) fattribute; if (handleDeclareErrorOrWarningAnnotation(model, frvs, fstruct) || handleDeclareParentsAnnotation(frvs, fstruct)) { // semantic check - must be in an @Aspect [remove if // previous block bypassed in advance] if (!type.isAnnotationStyleAspect() && !isCodeStyleAspect) { 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.
Params:
  • method –
  • type –
  • context –
  • msgHandler –
Returns:list of 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<AjAttribute> readAj5MethodAttributes(Method method, BcelMethod bMethod, ResolvedType type, ResolvedPointcutDefinition preResolvedPointcut, ISourceContext context, IMessageHandler msgHandler) { if (method.getName().startsWith(NameMangler.PREFIX)) { return Collections.emptyList(); // already dealt with by ajc... } AjAttributeMethodStruct struct = new AjAttributeMethodStruct(method, bMethod, 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 // // Note: we could actually skip the whole thing if type is not itself an // @Aspect // but then we would not see any warning. We do bypass for pointcut but // not for advice since it would // be too silent. boolean hasAtAspectJAnnotation = false; boolean hasAtAspectJAnnotationMustReturnVoid = false; for (int i = 0; i < attributes.length; i++) { Attribute attribute = attributes[i]; try { if (acceptAttribute(attribute)) { RuntimeAnnos rvs = (RuntimeAnnos) attribute; hasAtAspectJAnnotationMustReturnVoid = hasAtAspectJAnnotationMustReturnVoid || handleBeforeAnnotation(rvs, struct, preResolvedPointcut); hasAtAspectJAnnotationMustReturnVoid = hasAtAspectJAnnotationMustReturnVoid || handleAfterAnnotation(rvs, struct, preResolvedPointcut); hasAtAspectJAnnotationMustReturnVoid = hasAtAspectJAnnotationMustReturnVoid || handleAfterReturningAnnotation(rvs, struct, preResolvedPointcut, bMethod); hasAtAspectJAnnotationMustReturnVoid = hasAtAspectJAnnotationMustReturnVoid || handleAfterThrowingAnnotation(rvs, struct, preResolvedPointcut, bMethod); hasAtAspectJAnnotation = hasAtAspectJAnnotation || handleAroundAnnotation(rvs, struct, preResolvedPointcut); // there can only be one RuntimeVisible bytecode attribute break; } } catch (ReturningFormalNotDeclaredInAdviceSignatureException e) { msgHandler.handleMessage(new Message(WeaverMessages.format(WeaverMessages.RETURNING_FORMAL_NOT_DECLARED_IN_ADVICE, e.getFormalName()), IMessage.ERROR, null, bMethod.getSourceLocation())); } catch (ThrownFormalNotDeclaredInAdviceSignatureException e) { msgHandler.handleMessage(new Message(WeaverMessages.format(WeaverMessages.THROWN_FORMAL_NOT_DECLARED_IN_ADVICE, e.getFormalName()), IMessage.ERROR, null, bMethod.getSourceLocation())); } } hasAtAspectJAnnotation = hasAtAspectJAnnotation || hasAtAspectJAnnotationMustReturnVoid; // semantic check - must be in an @Aspect [remove if previous block // bypassed in advance] if (hasAtAspectJAnnotation && !type.isAspect()) { // 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 - advice must not be static if (hasAtAspectJAnnotation && struct.method.isStatic()) { msgHandler.handleMessage(MessageUtil.error("Advice cannot be declared static '" + methodToString(struct.method) + "'", type.getSourceLocation())); // new Message( // "Advice cannot be declared static '" + // 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.
Params:
  • field –
  • type –
  • context –
  • msgHandler –
Returns:list of AjAttributes, always empty for now
/** * 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<AjAttribute> readAj5FieldAttributes(Field field, BcelField bField, ResolvedType type, ISourceContext context, IMessageHandler msgHandler) { // Note: field annotation are for ITD and DEOW - processed at class // level directly return Collections.emptyList(); }
Read @Aspect
Params:
  • runtimeAnnotations –
  • struct –
Returns:true if found
/** * Read @Aspect * * @param runtimeAnnotations * @param struct * @return true if found */
private static boolean handleAspectAnnotation(RuntimeAnnos runtimeAnnotations, AjAttributeStruct struct) { AnnotationGen aspect = getAnnotation(runtimeAnnotations, AjcMemberMaker.ASPECT_ANNOTATION); if (aspect != null) { // semantic check for inheritance (only one level up) boolean extendsAspect = false; if (!"java.lang.Object".equals(struct.enclosingType.getSuperclass().getName())) { if (!struct.enclosingType.getSuperclass().isAbstract() && struct.enclosingType.getSuperclass().isAspect()) { reportError("cannot extend a concrete aspect", struct); return false; } extendsAspect = struct.enclosingType.getSuperclass().isAspect(); } NameValuePair aspectPerClause = getAnnotationElement(aspect, VALUE); final PerClause perClause; if (aspectPerClause == null) { // empty value means singleton unless inherited if (!extendsAspect) { perClause = new PerSingleton(); } else { perClause = new PerFromSuper(struct.enclosingType.getSuperclass().getPerClause().getKind()); } } 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.context.getOffset(), // struct.context.getOffset()+1);//FIXME // AVASM // Not setting version here // struct.ajAttributes.add(new AjAttribute.WeaverVersionInfo()); AjAttribute.Aspect aspectAttribute = new AjAttribute.Aspect(perClause); struct.ajAttributes.add(aspectAttribute); FormalBinding[] bindings = new org.aspectj.weaver.patterns.FormalBinding[0]; final IScope binding; binding = new BindingScope(struct.enclosingType, struct.context, bindings); // // we can't resolve here since the perclause typically refers // to pointcuts // // defined in the aspect that we haven't told the // BcelObjectType about yet. // // perClause.resolve(binding); // so we prepare to do it later... aspectAttribute.setResolutionScope(binding); return true; } } return false; }
Read a perClause, returns null on failure and issue messages
Params:
  • perClauseString – like "pertarget(.....)"
  • struct – for which we are parsing the per clause
Returns:a PerClause instance
/** * 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 pointcut = null; TypePattern typePattern = null; final PerClause perClause; if (perClauseString.startsWith(PerClause.KindAnnotationPrefix.PERCFLOW.getName())) { pointcutString = PerClause.KindAnnotationPrefix.PERCFLOW.extractPointcut(perClauseString); pointcut = parsePointcut(pointcutString, struct, false); perClause = new PerCflow(pointcut, false); } else if (perClauseString.startsWith(PerClause.KindAnnotationPrefix.PERCFLOWBELOW.getName())) { pointcutString = PerClause.KindAnnotationPrefix.PERCFLOWBELOW.extractPointcut(perClauseString); pointcut = parsePointcut(pointcutString, struct, false); perClause = new PerCflow(pointcut, true); } else if (perClauseString.startsWith(PerClause.KindAnnotationPrefix.PERTARGET.getName())) { pointcutString = PerClause.KindAnnotationPrefix.PERTARGET.extractPointcut(perClauseString); pointcut = parsePointcut(pointcutString, struct, false); perClause = new PerObject(pointcut, false); } else if (perClauseString.startsWith(PerClause.KindAnnotationPrefix.PERTHIS.getName())) { pointcutString = PerClause.KindAnnotationPrefix.PERTHIS.extractPointcut(perClauseString); pointcut = parsePointcut(pointcutString, struct, false); perClause = new PerObject(pointcut, 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()) && pointcut == 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
Params:
  • runtimeAnnotations –
  • struct –
Returns:true if found
/** * Read @DeclarePrecedence * * @param runtimeAnnotations * @param struct * @return true if found */
private static boolean handlePrecedenceAnnotation(RuntimeAnnos runtimeAnnotations, AjAttributeStruct struct) { AnnotationGen aspect = getAnnotation(runtimeAnnotations, AjcMemberMaker.DECLAREPRECEDENCE_ANNOTATION); if (aspect != null) { NameValuePair 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 @DeclareImplements // * // * @param runtimeAnnotations // * @param struct // * @return true if found // */ // private static boolean // handleDeclareImplementsAnnotation(RuntimeAnnotations runtimeAnnotations, // AjAttributeFieldStruct // struct) {//, ResolvedPointcutDefinition preResolvedPointcut) { // Annotation deci = getAnnotation(runtimeAnnotations, // AjcMemberMaker.DECLAREIMPLEMENTS_ANNOTATION); // if (deci != null) { // ElementNameValuePairGen deciPatternNVP = getAnnotationElement(deci, // VALUE); // String deciPattern = deciPatternNVP.getValue().stringifyValue(); // if (deciPattern != null) { // TypePattern typePattern = parseTypePattern(deciPattern, struct); // ResolvedType fieldType = // UnresolvedType.forSignature(struct.field.getSignature()).resolve(struct.enclosingType.getWorld()); // if (fieldType.isPrimitiveType()) { // return false; // } else if (fieldType.isInterface()) { // TypePattern parent = new // ExactTypePattern(UnresolvedType.forSignature(struct.field.getSignature()), // false, false); // parent.resolve(struct.enclosingType.getWorld()); // List parents = new ArrayList(1); // parents.add(parent); // //TODO kick ISourceLocation sl = struct.bField.getSourceLocation(); ?? // struct.ajAttributes.add( // new AjAttribute.DeclareAttribute( // new DeclareParents( // typePattern, // parents, // false // ) // ) // ); // return true; // } else { // reportError("@DeclareImplements: can only be used on field whose type is an interface", // struct); // return false; // } // } // } // return false; // } private static boolean handleDeclareParentsAnnotation(RuntimeAnnos runtimeAnnotations, AjAttributeFieldStruct struct) { AnnotationGen decpAnno = getAnnotation(runtimeAnnotations, AjcMemberMaker.DECLAREPARENTS_ANNOTATION); if (decpAnno != null) { NameValuePair decpPatternNameValuePair = getAnnotationElement(decpAnno, VALUE); String decpPattern = decpPatternNameValuePair.getValue().stringifyValue(); System.out.println("decpPatterNVP = "+decpPattern); if (decpPattern != null) { TypePattern typePattern = parseTypePattern(decpPattern, struct); ResolvedType fieldType = UnresolvedType.forSignature(struct.field.getSignature()).resolve( struct.enclosingType.getWorld()); if (fieldType.isParameterizedOrRawType()) { fieldType = fieldType.getGenericType(); } if (fieldType.isInterface()) { TypePattern parent = parseTypePattern(fieldType.getName(), struct); FormalBinding[] bindings = new org.aspectj.weaver.patterns.FormalBinding[0]; IScope binding = new BindingScope(struct.enclosingType, struct.context, bindings); // first add the declare implements like List<TypePattern> parents = new ArrayList<TypePattern>(1); parents.add(parent); DeclareParents dp = new DeclareParents(typePattern, parents, false); dp.resolve(binding); // resolves the parent and child parts of the decp // resolve this so that we can use it for the // MethodDelegateMungers below. // eg. '@Coloured *' will change from a WildTypePattern to // an 'AnyWithAnnotationTypePattern' after this resolution typePattern = dp.getChild(); // this retrieves the resolved version // TODO kick ISourceLocation sl = // struct.bField.getSourceLocation(); ?? // dp.setLocation(dp.getDeclaringType().getSourceContext(), // dp.getDeclaringType().getSourceLocation().getOffset(), // dp.getDeclaringType().getSourceLocation().getOffset()); dp.setLocation(struct.context, -1, -1); // not ideal... struct.ajAttributes.add(new AjAttribute.DeclareAttribute(dp)); // do we have a defaultImpl=xxx.class (ie implementation) String defaultImplClassName = null; NameValuePair defaultImplNVP = getAnnotationElement(decpAnno, "defaultImpl"); if (defaultImplNVP != null) { ClassElementValue defaultImpl = (ClassElementValue) defaultImplNVP.getValue(); defaultImplClassName = UnresolvedType.forSignature(defaultImpl.getClassString()).getName(); if (defaultImplClassName.equals("org.aspectj.lang.annotation.DeclareParents")) { defaultImplClassName = null; } else { // check public no arg ctor ResolvedType impl = struct.enclosingType.getWorld().resolve(defaultImplClassName, false); ResolvedMember[] mm = impl.getDeclaredMethods(); int implModifiers = impl.getModifiers(); boolean defaultVisibilityImpl = !(Modifier.isPrivate(implModifiers) || Modifier.isProtected(implModifiers) || Modifier.isPublic(implModifiers)); boolean hasNoCtorOrANoArgOne = true; ResolvedMember foundOneOfIncorrectVisibility = null; for (int i = 0; i < mm.length; i++) { ResolvedMember resolvedMember = mm[i]; if (resolvedMember.getName().equals("<init>")) { hasNoCtorOrANoArgOne = false; if (resolvedMember.getParameterTypes().length == 0) { if (defaultVisibilityImpl) { // default visibility implementation if (resolvedMember.isPublic() || resolvedMember.isDefault()) { hasNoCtorOrANoArgOne = true; } else { foundOneOfIncorrectVisibility = resolvedMember; } } else if (Modifier.isPublic(implModifiers)) { // public // implementation if (resolvedMember.isPublic()) { hasNoCtorOrANoArgOne = true; } else { foundOneOfIncorrectVisibility = resolvedMember; } } } } if (hasNoCtorOrANoArgOne) { break; } } if (!hasNoCtorOrANoArgOne) { if (foundOneOfIncorrectVisibility != null) { reportError( "@DeclareParents: defaultImpl=\"" + defaultImplClassName + "\" has a no argument constructor, but it is of incorrect visibility. It must be at least as visible as the type.", struct); } else { reportError("@DeclareParents: defaultImpl=\"" + defaultImplClassName + "\" has no public no-arg constructor", struct); } } if (!fieldType.isAssignableFrom(impl)) { reportError("@DeclareParents: defaultImpl=\"" + defaultImplClassName + "\" does not implement the interface '" + fieldType.toString() + "'", struct); } } } boolean hasAtLeastOneMethod = false; // then iterate on field interface hierarchy (not object) Iterator<ResolvedMember> methodIterator = fieldType.getMethodsIncludingIntertypeDeclarations(false, true); while (methodIterator.hasNext()) { ResolvedMember method = methodIterator.next(); if (method.isAbstract()) { // moved to be detected at weave time if the target // doesnt implement the methods // if (defaultImplClassName == null) { // // non marker interface with no default impl // provided // reportError("@DeclareParents: used with a non marker interface and no defaultImpl=\"...\" provided", // struct); // return false; // } hasAtLeastOneMethod = true; // What we are saying here: // We have this method 'method' and we want to put a // forwarding method into a type that matches // typePattern that should delegate to the version // of the method in 'defaultImplClassName' // Now the method may be from a supertype but the // declaring type of the method we pass into the // type // munger is what is used to determine the type of // the field that hosts the delegate instance. // So here we create a modified method with an // alternative declaring type so that we lookup // the right field. See pr164016. MethodDelegateTypeMunger mdtm = new MethodDelegateTypeMunger(method, struct.enclosingType, defaultImplClassName, typePattern); mdtm.setFieldType(fieldType); mdtm.setSourceLocation(struct.enclosingType.getSourceLocation()); struct.ajAttributes.add(new AjAttribute.TypeMunger(mdtm)); } } // successful so far, we thus need a bcel type munger to have // a field hosting the mixin in the target type if (hasAtLeastOneMethod && defaultImplClassName != null) { ResolvedMember fieldHost = AjcMemberMaker.itdAtDeclareParentsField(null, fieldType, struct.enclosingType); struct.ajAttributes.add(new AjAttribute.TypeMunger(new MethodDelegateTypeMunger.FieldHostTypeMunger( fieldHost, struct.enclosingType, typePattern))); } return true; } else { reportError("@DeclareParents: can only be used on a field whose type is an interface", struct); return false; } } } return false; }
Return a nicely formatted method string, for example: int X.foo(java.lang.String)
/** * Return a nicely formatted method string, for example: int X.foo(java.lang.String) */
public static String getMethodForMessage(AjAttributeMethodStruct methodstructure) { StringBuffer sb = new StringBuffer(); sb.append("Method '"); sb.append(methodstructure.method.getReturnType().toString()); sb.append(" ").append(methodstructure.enclosingType).append(".").append(methodstructure.method.getName()); sb.append("("); Type[] args = methodstructure.method.getArgumentTypes(); if (args != null) { for (int t = 0; t < args.length; t++) { if (t > 0) { sb.append(","); } sb.append(args[t].toString()); } } sb.append(")'"); return sb.toString(); }
Process any @DeclareMixin annotation. Example Declaration
"Foo+") public I createImpl(Object o) { return new Impl(o); }
Params:
  • runtimeAnnotations –
  • struct –
Returns:true if found
/** * Process any @DeclareMixin annotation. * * Example Declaration <br> * * @DeclareMixin("Foo+") public I createImpl(Object o) { return new Impl(o); } * * <br> * @param runtimeAnnotations * @param struct * @return true if found */
private static boolean handleDeclareMixinAnnotation(RuntimeAnnos runtimeAnnotations, AjAttributeMethodStruct struct) { AnnotationGen declareMixinAnnotation = getAnnotation(runtimeAnnotations, AjcMemberMaker.DECLAREMIXIN_ANNOTATION); if (declareMixinAnnotation == null) { // No annotation found return false; } Method annotatedMethod = struct.method; World world = struct.enclosingType.getWorld(); NameValuePair declareMixinPatternNameValuePair = getAnnotationElement(declareMixinAnnotation, VALUE); // declareMixinPattern could be of the form "Bar*" or "A || B" or "Foo+" String declareMixinPattern = declareMixinPatternNameValuePair.getValue().stringifyValue(); TypePattern targetTypePattern = parseTypePattern(declareMixinPattern, struct); // Return value of the annotated method is the interface or class that the mixin delegate should have ResolvedType methodReturnType = UnresolvedType.forSignature(annotatedMethod.getReturnType().getSignature()).resolve(world); if (methodReturnType.isParameterizedOrRawType()) { methodReturnType = methodReturnType.getGenericType(); } if (methodReturnType.isPrimitiveType()) { reportError(getMethodForMessage(struct) + ": factory methods for a mixin cannot return void or a primitive type", struct); return false; } if (annotatedMethod.getArgumentTypes().length > 1) { reportError(getMethodForMessage(struct) + ": factory methods for a mixin can take a maximum of one parameter", struct); return false; } // The set of interfaces to be mixed in is either: // supplied as a list in the 'Class[] interfaces' value in the annotation value // supplied as just the interface return value of the annotated method // supplied as just the class return value of the annotated method NameValuePair interfaceListSpecified = getAnnotationElement(declareMixinAnnotation, "interfaces"); List<TypePattern> newParents = new ArrayList<TypePattern>(1); List<ResolvedType> newInterfaceTypes = new ArrayList<ResolvedType>(1); if (interfaceListSpecified != null) { ArrayElementValue arrayOfInterfaceTypes = (ArrayElementValue) interfaceListSpecified.getValue(); int numberOfTypes = arrayOfInterfaceTypes.getElementValuesArraySize(); ElementValue[] theTypes = arrayOfInterfaceTypes.getElementValuesArray(); for (int i = 0; i < numberOfTypes; i++) { ClassElementValue interfaceType = (ClassElementValue) theTypes[i]; // Check: needs to be resolvable // TODO crappy replace required ResolvedType ajInterfaceType = UnresolvedType.forSignature(interfaceType.getClassString().replace("/", ".")) .resolve(world); if (ajInterfaceType.isMissing() || !ajInterfaceType.isInterface()) { reportError( "Types listed in the 'interfaces' DeclareMixin annotation value must be valid interfaces. This is invalid: " + ajInterfaceType.getName(), struct); // TODO better error location, use the method position return false; } if (!ajInterfaceType.isAssignableFrom(methodReturnType)) { reportError(getMethodForMessage(struct) + ": factory method does not return something that implements '" + ajInterfaceType.getName() + "'", struct); return false; } newInterfaceTypes.add(ajInterfaceType); // Checking that it is a superinterface of the methods return value is done at weave time TypePattern newParent = parseTypePattern(ajInterfaceType.getName(), struct); newParents.add(newParent); } } else { if (methodReturnType.isClass()) { reportError( getMethodForMessage(struct) + ": factory methods for a mixin must either return an interface type or specify interfaces in the annotation and return a class", struct); return false; } // Use the method return type: this might be a class or an interface TypePattern newParent = parseTypePattern(methodReturnType.getName(), struct); newInterfaceTypes.add(methodReturnType); newParents.add(newParent); } if (newParents.size() == 0) { // Warning: did they foolishly put @DeclareMixin(value="Bar+",interfaces={}) // TODO output warning return false; } // Create the declare parents that will add the interfaces to matching targets FormalBinding[] bindings = new org.aspectj.weaver.patterns.FormalBinding[0]; IScope binding = new BindingScope(struct.enclosingType, struct.context, bindings); // how do we mark this as a decp due to decmixin? DeclareParents dp = new DeclareParentsMixin(targetTypePattern, newParents); dp.resolve(binding); targetTypePattern = dp.getChild(); dp.setLocation(struct.context, -1, -1); // not ideal... struct.ajAttributes.add(new AjAttribute.DeclareAttribute(dp)); // The factory method for building the implementation is the // one attached to the annotation: // Method implementationFactory = struct.method; boolean hasAtLeastOneMethod = false; for (Iterator<ResolvedType> iterator = newInterfaceTypes.iterator(); iterator.hasNext();) { ResolvedType typeForDelegation = iterator.next(); // TODO check for overlapping interfaces. Eg. A implements I, I extends J - if they specify interfaces={I,J} we dont // want to do any methods twice ResolvedMember[] methods = typeForDelegation.getMethodsWithoutIterator(true, false, false).toArray( new ResolvedMember[0]); for (int i = 0; i < methods.length; i++) { ResolvedMember method = methods[i]; if (method.isAbstract()) { hasAtLeastOneMethod = true; if (method.hasBackingGenericMember()) { method = method.getBackingGenericMember(); } MethodDelegateTypeMunger mdtm = new MethodDelegateTypeMunger(method, struct.enclosingType, "", targetTypePattern, struct.method.getName(), struct.method.getSignature()); mdtm.setFieldType(methodReturnType); mdtm.setSourceLocation(struct.enclosingType.getSourceLocation()); struct.ajAttributes.add(new AjAttribute.TypeMunger(mdtm)); } } } // if any method delegate was created then a field to hold the delegate instance must also be added if (hasAtLeastOneMethod) { ResolvedMember fieldHost = AjcMemberMaker.itdAtDeclareParentsField(null, methodReturnType, struct.enclosingType); struct.ajAttributes.add(new AjAttribute.TypeMunger(new MethodDelegateTypeMunger.FieldHostTypeMunger(fieldHost, struct.enclosingType, targetTypePattern))); } return true; }
Read @Before
Params:
  • runtimeAnnotations –
  • struct –
Returns:true if found
/** * Read @Before * * @param runtimeAnnotations * @param struct * @return true if found */
private static boolean handleBeforeAnnotation(RuntimeAnnos runtimeAnnotations, AjAttributeMethodStruct struct, ResolvedPointcutDefinition preResolvedPointcut) { AnnotationGen before = getAnnotation(runtimeAnnotations, AjcMemberMaker.BEFORE_ANNOTATION); if (before != null) { NameValuePair beforeAdvice = getAnnotationElement(before, VALUE); if (beforeAdvice != null) { // this/target/args binding String argumentNames = getArgNamesValue(before); if (argumentNames != null) { struct.unparsedArgumentNames = argumentNames; } FormalBinding[] bindings = new org.aspectj.weaver.patterns.FormalBinding[0]; try { bindings = extractBindings(struct); } catch (UnreadableDebugInfoException unreadableDebugInfoException) { return false; } IScope binding = new BindingScope(struct.enclosingType, struct.context, bindings); // joinpoint, staticJoinpoint binding int extraArgument = extractExtraArgument(struct.method); Pointcut pc = null; if (preResolvedPointcut != null) { pc = preResolvedPointcut.getPointcut(); // pc.resolve(binding); } else { pc = parsePointcut(beforeAdvice.getValue().stringifyValue(), struct, false); if (pc == null) { return false;// parse error } pc = pc.resolve(binding); } setIgnoreUnboundBindingNames(pc, bindings); ISourceLocation sl = struct.context.makeSourceLocation(struct.bMethod.getDeclarationLineNumber(), struct.bMethod.getDeclarationOffset()); struct.ajAttributes.add(new AjAttribute.AdviceAttribute(AdviceKind.Before, pc, extraArgument, sl.getOffset(), sl .getOffset() + 1,// FIXME AVASM struct.context)); return true; } } return false; }
Read @After
Params:
  • runtimeAnnotations –
  • struct –
Returns:true if found
/** * Read @After * * @param runtimeAnnotations * @param struct * @return true if found */
private static boolean handleAfterAnnotation(RuntimeAnnos runtimeAnnotations, AjAttributeMethodStruct struct, ResolvedPointcutDefinition preResolvedPointcut) { AnnotationGen after = getAnnotation(runtimeAnnotations, AjcMemberMaker.AFTER_ANNOTATION); if (after != null) { NameValuePair afterAdvice = getAnnotationElement(after, VALUE); if (afterAdvice != null) { // this/target/args binding FormalBinding[] bindings = new org.aspectj.weaver.patterns.FormalBinding[0]; String argumentNames = getArgNamesValue(after); if (argumentNames != null) { struct.unparsedArgumentNames = argumentNames; } try { bindings = extractBindings(struct); } catch (UnreadableDebugInfoException unreadableDebugInfoException) { return false; } IScope binding = new BindingScope(struct.enclosingType, struct.context, 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, false); if (pc == null) { return false;// parse error } pc.resolve(binding); } setIgnoreUnboundBindingNames(pc, bindings); ISourceLocation sl = struct.context.makeSourceLocation(struct.bMethod.getDeclarationLineNumber(), struct.bMethod.getDeclarationOffset()); struct.ajAttributes.add(new AjAttribute.AdviceAttribute(AdviceKind.After, pc, extraArgument, sl.getOffset(), sl .getOffset() + 1,// FIXME AVASM struct.context)); return true; } } return false; }
Read @AfterReturning
Params:
  • runtimeAnnotations –
  • struct –
Returns:true if found
/** * Read @AfterReturning * * @param runtimeAnnotations * @param struct * @return true if found */
private static boolean handleAfterReturningAnnotation(RuntimeAnnos runtimeAnnotations, AjAttributeMethodStruct struct, ResolvedPointcutDefinition preResolvedPointcut, BcelMethod owningMethod) throws ReturningFormalNotDeclaredInAdviceSignatureException { AnnotationGen after = getAnnotation(runtimeAnnotations, AjcMemberMaker.AFTERRETURNING_ANNOTATION); if (after != null) { NameValuePair annValue = getAnnotationElement(after, VALUE); NameValuePair annPointcut = getAnnotationElement(after, POINTCUT); NameValuePair 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; } else { // check that thrownFormal exists as the last parameter in // the advice String[] pNames = owningMethod.getParameterNames(); if (pNames == null || pNames.length == 0 || !Arrays.asList(pNames).contains(returned)) { throw new ReturningFormalNotDeclaredInAdviceSignatureException(returned); } } } String argumentNames = getArgNamesValue(after); if (argumentNames != null) { struct.unparsedArgumentNames = argumentNames; } // 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, struct.context, 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, false); if (pc == null) { return false;// parse error } pc.resolve(binding); } setIgnoreUnboundBindingNames(pc, bindings); ISourceLocation sl = struct.context.makeSourceLocation(struct.bMethod.getDeclarationLineNumber(), struct.bMethod.getDeclarationOffset()); struct.ajAttributes.add(new AjAttribute.AdviceAttribute(AdviceKind.AfterReturning, pc, extraArgument, sl.getOffset(), sl.getOffset() + 1,// FIXME AVASM struct.context)); return true; } return false; }
Read @AfterThrowing
Params:
  • runtimeAnnotations –
  • struct –
Returns:true if found
/** * Read @AfterThrowing * * @param runtimeAnnotations * @param struct * @return true if found */
private static boolean handleAfterThrowingAnnotation(RuntimeAnnos runtimeAnnotations, AjAttributeMethodStruct struct, ResolvedPointcutDefinition preResolvedPointcut, BcelMethod owningMethod) throws ThrownFormalNotDeclaredInAdviceSignatureException { AnnotationGen after = getAnnotation(runtimeAnnotations, AjcMemberMaker.AFTERTHROWING_ANNOTATION); if (after != null) { NameValuePair annValue = getAnnotationElement(after, VALUE); NameValuePair annPointcut = getAnnotationElement(after, POINTCUT); NameValuePair annThrown = getAnnotationElement(after, THROWING); // extract the pointcut and throwned type/binding - do some checks String pointcut = null; String thrownFormal = 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 (annThrown != null) { thrownFormal = annThrown.getValue().stringifyValue(); if (isNullOrEmpty(thrownFormal)) { thrownFormal = null; } else { // check that thrownFormal exists as the last parameter in // the advice String[] pNames = owningMethod.getParameterNames(); if (pNames == null || pNames.length == 0 || !Arrays.asList(pNames).contains(thrownFormal)) { throw new ThrownFormalNotDeclaredInAdviceSignatureException(thrownFormal); } } } String argumentNames = getArgNamesValue(after); if (argumentNames != null) { struct.unparsedArgumentNames = argumentNames; } // 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 = (thrownFormal == null ? extractBindings(struct) : extractBindings(struct, thrownFormal)); } catch (UnreadableDebugInfoException unreadableDebugInfoException) { return false; } IScope binding = new BindingScope(struct.enclosingType, struct.context, bindings); // joinpoint, staticJoinpoint binding int extraArgument = extractExtraArgument(struct.method); // return binding if (thrownFormal != null) { extraArgument |= Advice.ExtraArgument; } Pointcut pc = null; if (preResolvedPointcut != null) { pc = preResolvedPointcut.getPointcut(); } else { pc = parsePointcut(pointcut, struct, false); if (pc == null) { return false;// parse error } pc.resolve(binding); } setIgnoreUnboundBindingNames(pc, bindings); ISourceLocation sl = struct.context.makeSourceLocation(struct.bMethod.getDeclarationLineNumber(), struct.bMethod.getDeclarationOffset()); struct.ajAttributes.add(new AjAttribute.AdviceAttribute(AdviceKind.AfterThrowing, pc, extraArgument, sl.getOffset(), sl .getOffset() + 1, struct.context)); return true; } return false; }
Read @Around
Params:
  • runtimeAnnotations –
  • struct –
Returns:true if found
/** * Read @Around * * @param runtimeAnnotations * @param struct * @return true if found */
private static boolean handleAroundAnnotation(RuntimeAnnos runtimeAnnotations, AjAttributeMethodStruct struct, ResolvedPointcutDefinition preResolvedPointcut) { AnnotationGen around = getAnnotation(runtimeAnnotations, AjcMemberMaker.AROUND_ANNOTATION); if (around != null) { NameValuePair aroundAdvice = getAnnotationElement(around, VALUE); if (aroundAdvice != null) { // this/target/args binding String argumentNames = getArgNamesValue(around); if (argumentNames != null) { struct.unparsedArgumentNames = argumentNames; } FormalBinding[] bindings = new org.aspectj.weaver.patterns.FormalBinding[0]; try { bindings = extractBindings(struct); } catch (UnreadableDebugInfoException unreadableDebugInfoException) { return false; } IScope binding = new BindingScope(struct.enclosingType, struct.context, 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, false); if (pc == null) { return false;// parse error } pc.resolve(binding); } setIgnoreUnboundBindingNames(pc, bindings); ISourceLocation sl = struct.context.makeSourceLocation(struct.bMethod.getDeclarationLineNumber(), struct.bMethod.getDeclarationOffset()); struct.ajAttributes.add(new AjAttribute.AdviceAttribute(AdviceKind.Around, pc, extraArgument, sl.getOffset(), sl .getOffset() + 1,// FIXME AVASM struct.context)); return true; } } return false; }
Read @Pointcut and handle the resolving in a lazy way to deal with pointcut references
Params:
  • runtimeAnnotations –
  • struct –
Returns:true if a pointcut was handled
/** * Read @Pointcut and handle the resolving in a lazy way to deal with pointcut references * * @param runtimeAnnotations * @param struct * @return true if a pointcut was handled */
private static boolean handlePointcutAnnotation(RuntimeAnnos runtimeAnnotations, AjAttributeMethodStruct struct) { AnnotationGen pointcut = getAnnotation(runtimeAnnotations, AjcMemberMaker.POINTCUT_ANNOTATION); if (pointcut == null) { return false; } NameValuePair pointcutExpr = getAnnotationElement(pointcut, VALUE); // semantic check: the method must return void, or be // "public static boolean" for if() support if (!(Type.VOID.equals(struct.method.getReturnType()) || (Type.BOOLEAN.equals(struct.method.getReturnType()) && struct.method.isStatic() && struct.method.isPublic()))) { reportWarning("Found @Pointcut on a method not returning 'void' or not 'public static boolean'", 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 } String argumentNames = getArgNamesValue(pointcut); if (argumentNames != null) { struct.unparsedArgumentNames = argumentNames; } // this/target/args binding final IScope binding; try { if (struct.method.isAbstract()) { binding = null; } else { binding = new BindingScope(struct.enclosingType, struct.context, extractBindings(struct)); } } catch (UnreadableDebugInfoException e) { return false; } UnresolvedType[] argumentTypes = new UnresolvedType[struct.method.getArgumentTypes().length]; for (int i = 0; i < argumentTypes.length; i++) { argumentTypes[i] = UnresolvedType.forSignature(struct.method.getArgumentTypes()[i].getSignature()); } Pointcut pc = null; if (struct.method.isAbstract()) { if ((pointcutExpr != null && isNullOrEmpty(pointcutExpr.getValue().stringifyValue())) || pointcutExpr == null) { // abstract pointcut // leave pc = null } else { reportError("Found defined @Pointcut on an abstract method", struct); return false;// stop } } else { if (pointcutExpr == null || isNullOrEmpty(pointcutExpr.getValue().stringifyValue())) { // the matches nothing pointcut (125475/125480) - perhaps not as // cleanly supported as it could be. } else { // if (pointcutExpr != null) { // 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 pc = parsePointcut(pointcutExpr.getValue().stringifyValue(), struct, true); if (pc == null) { return false;// parse error } pc.setLocation(struct.context, -1, -1);// FIXME AVASM !! bMethod // is null here.. // } else { // reportError("Found undefined @Pointcut on a non-abstract method", // struct); // return false; // } } } // do not resolve binding now but lazily struct.ajAttributes.add(new AjAttribute.PointcutDeclarationAttribute(new LazyResolvedPointcutDefinition( struct.enclosingType, struct.method.getModifiers(), struct.method.getName(), argumentTypes, UnresolvedType .forSignature(struct.method.getReturnType().getSignature()), pc,// can // be // null // for // abstract // pointcut binding // can be null for abstract pointcut ))); return true; }
Read @DeclareError, @DeclareWarning
Params:
  • runtimeAnnotations –
  • struct –
Returns:true if found
/** * Read @DeclareError, @DeclareWarning * * @param runtimeAnnotations * @param struct * @return true if found */
private static boolean handleDeclareErrorOrWarningAnnotation(AsmManager model, RuntimeAnnos runtimeAnnotations, AjAttributeFieldStruct struct) { AnnotationGen error = getAnnotation(runtimeAnnotations, AjcMemberMaker.DECLAREERROR_ANNOTATION); boolean hasError = false; if (error != null) { NameValuePair 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; } Pointcut pc = parsePointcut(declareError.getValue().stringifyValue(), struct, false); if (pc == null) { hasError = false;// cannot parse pointcut } else { DeclareErrorOrWarning deow = new DeclareErrorOrWarning(true, pc, struct.field.getConstantValue().toString()); setDeclareErrorOrWarningLocation(model, deow, struct); struct.ajAttributes.add(new AjAttribute.DeclareAttribute(deow)); hasError = true; } } } AnnotationGen warning = getAnnotation(runtimeAnnotations, AjcMemberMaker.DECLAREWARNING_ANNOTATION); boolean hasWarning = false; if (warning != null) { NameValuePair 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; } Pointcut pc = parsePointcut(declareWarning.getValue().stringifyValue(), struct, false); if (pc == null) { hasWarning = false;// cannot parse pointcut } else { DeclareErrorOrWarning deow = new DeclareErrorOrWarning(false, pc, struct.field.getConstantValue().toString()); setDeclareErrorOrWarningLocation(model, deow, struct); struct.ajAttributes.add(new AjAttribute.DeclareAttribute(deow)); return hasWarning = true; } } } return hasError || hasWarning; }
Sets the location for the declare error / warning using the corresponding IProgramElement in the structure model. This will only fix bug 120356 if compiled with -emacssym, however, it does mean that the cross references view in AJDT will show the correct information. Other possibilities for fix: 1. using the information in ajcDeclareSoft (if this is set correctly) which will fix the problem if compiled with ajc but not if compiled with javac. 2. creating an AjAttribute called FieldDeclarationLineNumberAttribute (much like MethodDeclarationLineNumberAttribute) which we can ask for the offset. This will again only fix bug 120356 when compiled with ajc.
Params:
  • deow –
  • struct –
/** * Sets the location for the declare error / warning using the corresponding IProgramElement in the structure model. This will * only fix bug 120356 if compiled with -emacssym, however, it does mean that the cross references view in AJDT will show the * correct information. * * Other possibilities for fix: 1. using the information in ajcDeclareSoft (if this is set correctly) which will fix the problem * if compiled with ajc but not if compiled with javac. 2. creating an AjAttribute called FieldDeclarationLineNumberAttribute * (much like MethodDeclarationLineNumberAttribute) which we can ask for the offset. This will again only fix bug 120356 when * compiled with ajc. * * @param deow * @param struct */
private static void setDeclareErrorOrWarningLocation(AsmManager model, DeclareErrorOrWarning deow, AjAttributeFieldStruct struct) { IHierarchy top = (model == null ? null : model.getHierarchy()); if (top != null && top.getRoot() != null) { IProgramElement ipe = top.findElementForLabel(top.getRoot(), IProgramElement.Kind.FIELD, struct.field.getName()); if (ipe != null && ipe.getSourceLocation() != null) { ISourceLocation sourceLocation = ipe.getSourceLocation(); int start = sourceLocation.getOffset(); int end = start + struct.field.getName().length(); deow.setLocation(struct.context, start, end); return; } } deow.setLocation(struct.context, -1, -1); }
Returns a readable representation of a method. Method.toString() is not suitable.
Params:
  • method –
Returns:a readable representation of a method
/** * Returns a readable representation of a method. Method.toString() is not suitable. * * @param method * @return a readable representation of a method */
private static String methodToString(Method method) { StringBuffer sb = new StringBuffer(); sb.append(method.getName()); sb.append(method.getSignature()); return sb.toString(); }
Build the bindings for a given method (pointcut / advice)
Params:
  • struct –
Returns:null if no debug info is available
/** * 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<FormalBinding> bindings = new ArrayList<FormalBinding>(); for (int i = 0; i < argumentNames.length; i++) { String argumentName = argumentNames[i]; UnresolvedType argumentType = UnresolvedType.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 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
Params:
  • method –
Returns:extra arg flag
/** * Compute the flag for the xxxJoinPoint extra argument * * @param method * @return extra arg flag */
private static int extractExtraArgument(Method method) { Type[] methodArgs = method.getArgumentTypes(); String[] sigs = new String[methodArgs.length]; for (int i = 0; i < methodArgs.length; i++) { sigs[i] = methodArgs[i].getSignature(); } return extractExtraArgument(sigs); }
Compute the flag for the xxxJoinPoint extra argument
Params:
  • argumentSignatures –
Returns:extra arg flag
/** * Compute the flag for the xxxJoinPoint extra argument * * @param argumentSignatures * @return extra arg flag */
public static int extractExtraArgument(String[] argumentSignatures) { int extraArgument = 0; for (int i = 0; i < argumentSignatures.length; i++) { if (AjcMemberMaker.TYPEX_JOINPOINT.getSignature().equals(argumentSignatures[i])) { extraArgument |= Advice.ThisJoinPoint; } else if (AjcMemberMaker.TYPEX_PROCEEDINGJOINPOINT.getSignature().equals(argumentSignatures[i])) { extraArgument |= Advice.ThisJoinPoint; } else if (AjcMemberMaker.TYPEX_STATICJOINPOINT.getSignature().equals(argumentSignatures[i])) { extraArgument |= Advice.ThisJoinPointStaticPart; } else if (AjcMemberMaker.TYPEX_ENCLOSINGSTATICJOINPOINT.getSignature().equals(argumentSignatures[i])) { extraArgument |= Advice.ThisEnclosingJoinPointStaticPart; } } return extraArgument; }
Returns the runtime (RV/RIV) annotation of type annotationType or null if no such annotation
Params:
  • rvs –
  • annotationType –
Returns:annotation
/** * Returns the runtime (RV/RIV) annotation of type annotationType or null if no such annotation * * @param rvs * @param annotationType * @return annotation */
private static AnnotationGen getAnnotation(RuntimeAnnos rvs, UnresolvedType annotationType) { final String annotationTypeName = annotationType.getName(); for (AnnotationGen rv : rvs.getAnnotations()) { 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.
Params:
  • annotation –
  • elementName –
Returns:annotation NVP
/** * 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 annotation NVP */
private static NameValuePair getAnnotationElement(AnnotationGen annotation, String elementName) { for (NameValuePair element : annotation.getValues()) { if (elementName.equals(element.getNameString())) { return element; } } return null; }
Return the argNames set for an annotation or null if it is not specified.
/** * Return the argNames set for an annotation or null if it is not specified. */
private static String getArgNamesValue(AnnotationGen anno) { List<NameValuePair> elements = anno.getValues(); for (NameValuePair element : elements) { if (ARGNAMES.equals(element.getNameString())) { return element.getValue().stringifyValue(); } } return null; } private static String lastbit(String fqname) { int i = fqname.lastIndexOf("."); if (i == -1) { return fqname; } else { return fqname.substring(i + 1); } }
Extract the method argument names. First we try the debug info attached to the method (the LocalVariableTable) - if we cannot find that we look to use the argNames value that may have been supplied on the associated annotation. If that fails we just don't know and return an empty string.
Params:
  • method –
  • argNamesFromAnnotation –
  • methodStruct –
Returns:method argument names
/** * Extract the method argument names. First we try the debug info attached to the method (the LocalVariableTable) - if we cannot * find that we look to use the argNames value that may have been supplied on the associated annotation. If that fails we just * don't know and return an empty string. * * @param method * @param argNamesFromAnnotation * @param methodStruct * @return method argument names */
private static String[] getMethodArgumentNames(Method method, String argNamesFromAnnotation, AjAttributeMethodStruct methodStruct) { if (method.getArgumentTypes().length == 0) { return EMPTY_STRINGS; } final int startAtStackIndex = method.isStatic() ? 0 : 1; final List<MethodArgument> arguments = new ArrayList<MethodArgument>(); LocalVariableTable lt = method.getLocalVariableTable(); if (lt != null) { LocalVariable[] lvt = lt.getLocalVariableTable(); for (int j = 0; j < lvt.length; j++) { LocalVariable localVariable = lvt[j]; if (localVariable != null) { // pr348488 if (localVariable.getStartPC() == 0) { if (localVariable.getIndex() >= startAtStackIndex) { arguments.add(new MethodArgument(localVariable.getName(), localVariable.getIndex())); } } } else { String typename = (methodStruct.enclosingType != null ? methodStruct.enclosingType.getName() : ""); System.err.println("AspectJ: 348488 debug: unusual local variable table for method " + typename + "." + method.getName()); } } if (arguments.size() == 0) { // The local variable table is causing us trouble, try the annotation value // See 539121 for a jacoco variant of the cobertura issue below if (argNamesFromAnnotation != null) { String[] argNames = extractArgNamesFromAnnotationValue(method, argNamesFromAnnotation, methodStruct); if (argNames.length != 0) { return argNames; } } // could be cobertura code where some extra bytecode has been stuffed in at the start of the method // but the local variable table hasn't been repaired - for example: // LocalVariable(start_pc = 6, length = 40, index = 0:com.example.ExampleAspect this) // LocalVariable(start_pc = 6, length = 40, index = 1:org.aspectj.lang.ProceedingJoinPoint pjp) // LocalVariable(start_pc = 6, length = 40, index = 2:int __cobertura__line__number__) // LocalVariable(start_pc = 6, length = 40, index = 3:int __cobertura__branch__number__) LocalVariable localVariable = lvt[0]; if (localVariable != null) { // pr348488 if (localVariable.getStartPC() != 0) { // looks suspicious so let's use this information for (int j = 0; j < lvt.length && arguments.size() < method.getArgumentTypes().length; j++) { localVariable = lvt[j]; if (localVariable.getIndex() >= startAtStackIndex) { arguments.add(new MethodArgument(localVariable.getName(), localVariable.getIndex())); } } } } } } else { if (argNamesFromAnnotation != null) { String[] argNames = extractArgNamesFromAnnotationValue(method, argNamesFromAnnotation, methodStruct); if (argNames != null) { return argNames; } } } if (arguments.size() != method.getArgumentTypes().length) { return EMPTY_STRINGS; } // sort by index Collections.sort(arguments, new Comparator<MethodArgument>() { public int compare(MethodArgument mo, MethodArgument mo1) { 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 (MethodArgument methodArgument : arguments) { argumentNames[i++] = methodArgument.name; } return argumentNames; } private static String[] extractArgNamesFromAnnotationValue(Method method, String argNamesFromAnnotation, AjAttributeMethodStruct methodStruct) { StringTokenizer st = new StringTokenizer(argNamesFromAnnotation, " ,"); List<String> args = new ArrayList<String>(); while (st.hasMoreTokens()) { args.add(st.nextToken()); } if (args.size() != method.getArgumentTypes().length) { StringBuffer shortString = new StringBuffer().append(lastbit(method.getReturnType().toString())).append(" ") .append(method.getName()); if (method.getArgumentTypes().length > 0) { shortString.append("("); for (int i = 0; i < method.getArgumentTypes().length; i++) { shortString.append(lastbit(method.getArgumentTypes()[i].toString())); if ((i + 1) < method.getArgumentTypes().length) { shortString.append(","); } } shortString.append(")"); } reportError("argNames annotation value does not specify the right number of argument names for the method '" + shortString.toString() + "'", methodStruct); return EMPTY_STRINGS; } return args.toArray(new String[] {}); }
A method argument, used for sorting by indexOnStack (ie order in signature)
Author:Alexandre Vasseur
/** * 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; } }
LazyResolvedPointcutDefinition lazyly resolve the pointcut so that we have time to register all pointcut referenced before pointcut resolution happens
Author:Alexandre Vasseur
/** * 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 final Pointcut m_pointcutUnresolved; // null for abstract // pointcut private final IScope m_binding; private Pointcut m_lazyPointcut = null; public LazyResolvedPointcutDefinition(UnresolvedType declaringType, int modifiers, String name, UnresolvedType[] parameterTypes, UnresolvedType returnType, Pointcut pointcut, IScope binding) { super(declaringType, modifiers, name, parameterTypes, returnType, Pointcut.makeMatchesNothing(Pointcut.RESOLVED)); m_pointcutUnresolved = pointcut; m_binding = binding; } @Override public Pointcut getPointcut() { if (m_lazyPointcut == null && m_pointcutUnresolved == null) { m_lazyPointcut = Pointcut.makeMatchesNothing(Pointcut.CONCRETE); } if (m_lazyPointcut == null && m_pointcutUnresolved != null) { m_lazyPointcut = m_pointcutUnresolved.resolve(m_binding); m_lazyPointcut.copyLocationFrom(m_pointcutUnresolved); } return m_lazyPointcut; } }
Helper to test empty strings
Params:
  • s –
Returns:true if empty or null
/** * Helper to test empty strings * * @param s * @return true if empty or null */
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
Params:
  • pointcut –
  • bindings –
/** * 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<String> ignores = new ArrayList<String>(); for (int i = 0; i < bindings.length; i++) { FormalBinding formalBinding = bindings[i]; if (formalBinding instanceof FormalBinding.ImplicitFormalBinding) { ignores.add(formalBinding.getName()); } } pointcut.m_ignoreUnboundBindingForNames = ignores.toArray(new String[ignores.size()]); }
A check exception when we cannot read debug info (needed for formal binding)
/** * A check exception when we cannot read debug info (needed for formal binding) */
private static class UnreadableDebugInfoException extends Exception { }
Report an error
Params:
  • message –
  • location –
/** * 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)); } } // private static void reportError(String message, IMessageHandler handler, ISourceLocation sourceLocation) { // if (!handler.isIgnoring(IMessage.ERROR)) { // handler.handleMessage(new Message(message, sourceLocation, true)); // } // }
Report a warning
Params:
  • message –
  • location –
/** * 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
Params:
  • pointcutString –
  • struct –
  • allowIf –
Returns:pointcut, unresolved
/** * Parse the given pointcut, return null on failure and issue an error * * @param pointcutString * @param struct * @param allowIf * @return pointcut, unresolved */
private static Pointcut parsePointcut(String pointcutString, AjAttributeStruct struct, boolean allowIf) { try { PatternParser parser = new PatternParser(pointcutString, struct.context); Pointcut pointcut = parser.parsePointcut(); parser.checkEof(); pointcut.check(null, struct.enclosingType.getWorld()); if (!allowIf && pointcutString.indexOf("if()") >= 0 && hasIf(pointcut)) { reportError("if() pointcut is not allowed at this pointcut location '" + pointcutString + "'", struct); return null; } pointcut.setLocation(struct.context, -1, -1);// FIXME -1,-1 is not // good enough return pointcut; } catch (ParserException e) { reportError("Invalid pointcut '" + pointcutString + "': " + e.toString() + (e.getLocation() == null ? "" : " at position " + e.getLocation().getStart()), struct); return null; } } private static boolean hasIf(Pointcut pointcut) { IfFinder visitor = new IfFinder(); pointcut.accept(visitor, null); return visitor.hasIf; }
Parse the given type pattern, return null on failure and issue an error
Params:
  • patternString –
  • location –
Returns:type pattern
/** * Parse the given type pattern, return null on failure and issue an error * * @param patternString * @param location * @return type pattern */
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; } } static class ThrownFormalNotDeclaredInAdviceSignatureException extends Exception { private final String formalName; public ThrownFormalNotDeclaredInAdviceSignatureException(String formalName) { this.formalName = formalName; } public String getFormalName() { return formalName; } } static class ReturningFormalNotDeclaredInAdviceSignatureException extends Exception { private final String formalName; public ReturningFormalNotDeclaredInAdviceSignatureException(String formalName) { this.formalName = formalName; } public String getFormalName() { return formalName; } } }