1

I am trying to learn AspectJ and figuring out how to retrieve specific joinpoints at certain points in a flow. My example is something like this:

I want to run an unit test annotated with JUnit's @Test then any methods called in that test that may be in another class annotated with another annotation, let's say @Example, then I could access basically the entire flow at those certain points so I had the ability to get the class name/method name of the test annotated with @Test and then also get the method information for the method annotated @Example. I've included some example code for clarification:

Test class:

public class ExampleTest {
  @Test
  public void shouldTestSomething() {
    ExampleClass exampleClazz = new ExampleClass();
    exampleClazz.something();
    // ...
  }

POJO:

public class ExampleClass {
  @Example
  public void something() {
    // do something
  end
end

So with these classes, I would like to make an aspect that would basically find any kind of @Example called within a @Test so I can then have access to both (or more) join points where I can grab the method/class signatures from the AspectJ JoinPoint object.

I tried something like this:

@Aspect
public class ExampleAspect {
  @Pointcut("execution(@org.junit.Test * *(..)) 
             && !within(ExampleAspect)")
  public void testPointCut() {}

  @Pointcut("@annotation(com.example.Example)")
  public void examplePointCut() {}

  @After("cflow(testPointCut) && examplePointCut()")
  public void doSomething(JoinPoint joinPoint) {
    System.out.println(joinPoint.getSignature());
  }
}

But the output looks like this:

void ExampleTest.ExampleClass.something()

The main issue is that it is missing the name of the test method (shouldTestSomething()) in the signature. What would be the best way to retrieve that?

user1076802
  • 317
  • 1
  • 4
  • 15

1 Answers1

2

Not sure if I understand correctly, but if you need to access information about the context from where a piece of code under a join point of your interest gets called, then what you need is the thisEnclosingJoinPointStaticPart (in native AspectJ syntax). If you are using AspectJ 5 annotation style aspects, just add a parameter to your advice method with the type JoinPoint.EnclosingStaticPart.

Note that this is not available for execution() style pointcuts, only for call() style pointcuts, otherwise the JoinPoint.EnclosingStaticPart and JoinPoint.StaticPart will be the same.

This means you need to rewrite your aspect in the following way:

@Aspect
public class ExampleAspect {

    @Pointcut("execution(@org.junit.Test * *(..)) && !within(ExampleAspect)")
    public void testPointCut() {
    }

    @Pointcut("call(@com.example.Example * *(..))")
    public void examplePointCut() {
    }

    @After("cflow(testPointCut()) && examplePointCut()")
    public void doSomething(JoinPoint joinPoint, EnclosingStaticPart enclosingStaticPart) {
        System.out.println(joinPoint.getSignature() + " was invoked from "
            + enclosingStaticPart.getSignature());
    }

}

The output with your test code would be:

void q35991663.com.example.ExampleClass.something() was invoked from void q35991663.com.example.ExampleTest.shouldTestSomething()

I also rewrote your examplePointCut. The pointcut expression @annotation(com.example.Example) would mean

any join point where the subject has an annotation of type com.example.Example

which would include both execution() and call() type join points. We need only the call() join points in this case, so @annotation() isn't even necessary if you are not planning to bind the value of the annotation to the advice context.

Nándor Előd Fekete
  • 6,988
  • 1
  • 22
  • 47