avenue68
avenue68

Reputation: 53

how to pick set joinpoints in specific methods in AspectJ

I'm developing an Advice and I want to make it advise only on field sets in specific methods. I tried cflow(pointcutForSpecificMethod()) && set(* *) pointcut expression but it picks field sets in other methods under control flow of specific methods.

Any idea?

Upvotes: 0

Views: 148

Answers (1)

kriegaex
kriegaex

Reputation: 67317

This is not possible directly with an exact pointcut expression, but you can use if() pointcuts to dynamically determine from the stack trace or - like in this case - from the enclosing join point static part exposed by AspectJ - what the executing method is. Here is a little example and an aspect in two variants: native syntax (my preference, more elegant and less boilerplate) and annotation-style syntax:

package de.scrum_master.app;

public class Application {
  private int field = 0;

  public static void main(String[] args) {
    Application app = new Application();
    app.foo(11);
    app.bar(22);
  }

  public void foo(int i) {
    field = i;
    bar(2 * i);
  }

  void bar(int i) {
    field = i;
  }
}
package de.scrum_master.aspect;

import org.aspectj.lang.JoinPoint;

public aspect MyAspectNative {
  pointcut pointcutForSpecificMethod() : execution(* foo(*));

  public static boolean executingMethodMatches(JoinPoint.StaticPart staticPart) {
    return staticPart.getSignature().toLongString().contains("de.scrum_master.app.Application.foo(int)");
  }

  before() :
    cflow(pointcutForSpecificMethod()) && set(* *) &&
    if(executingMethodMatches(thisEnclosingJoinPointStaticPart))
  {
    System.out.println(thisEnclosingJoinPointStaticPart);
    System.out.println(thisJoinPoint);
  }
}
package de.scrum_master.aspect;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;

@Aspect
public class MyAspect {
  @Pointcut("execution(* foo(*))")
  private static void pointcutForSpecificMethod() {}

  @Pointcut("if()")
  public static boolean executingMethodMatches(JoinPoint.EnclosingStaticPart staticPart) {
    return staticPart.getSignature().toLongString().contains("de.scrum_master.app.Application.foo(int)");
  }

  @Before(
    "cflow(pointcutForSpecificMethod()) && set(* *) && " +
    "executingMethodMatches(thisEnclosingJoinPointStaticPart)"
  )
  public void beforeAdvice(JoinPoint thisJoinPoint, JoinPoint.EnclosingStaticPart thisEnclosingJoinPointStaticPart)
  {
    System.out.println(thisEnclosingJoinPointStaticPart);
    System.out.println(thisJoinPoint);
  }
}

I tried to keep the two aspects as similar as possible structurally. No matter which aspect syntax variant you choose, the output will be:

execution(void de.scrum_master.app.Application.foo(int))
set(int de.scrum_master.app.Application.field)

Upvotes: 1

Related Questions