I need to write an aspect (let's call it A) that shows all the executed pointcuts at runtime. Is there a way to write a pointcut like call(...) that points directly to another pointcut without using the aspects' names ?
I've written something that uses mostly calls to generic functions and within() so that when a function in a aspect is called my aspect A prints something. I feel that it's not an ideal solution because I'd always need to write all the aspects names and would be to long with many aspects.
public class Main {
public static void main(String[] args) {
ClassA a = new ClassA();
a.methodA();
a.methodA();
a.methodB();
a.methodA();
}
}
public class ClassA {
public void methodA() {
System.out.println("MethodA");
}
public void methodB() {
System.out.println("MethodB");
}
public void methodC() {
System.out.println("MethodC");
}
}
public aspect MethodAAspect {
pointcut MethA():
call(public * ClassA.methodA());
pointcut MethC():
call(public * ClassA.methodC());
after():
MethA() {
System.out.println("Aspect here, methodA ended.");
}
after():
MethC() {
System.out.println("Aspect here, methodC ended.");
}
}
If, in this example, I'd need an aspect that counts how many times all pointcuts have been executed or prints something when a pointcut is executed how should I write it?
I am not sure I understand correctly what you want to achieve because your description is somewhat imprecise. For example, a pointcut is not "executed", an application method or an advice inside an aspect are. So I am not sure if you want to just log each method call (or maybe method execution, see below for the difference) or maybe need some kind of meta aspect which counts how many times aspect advices are being executed. I am assuming the former, simpler case here because it makes most sense to me.
Your application code, but with package names:
package de.scrum_master.app;
public class ClassA {
public void methodA() {
System.out.println("MethodA");
}
public void methodB() {
System.out.println("MethodB");
}
public void methodC() {
System.out.println("MethodC");
}
}
package de.scrum_master.app;
public class Main {
public static void main(String[] args) {
ClassA a = new ClassA();
a.methodA();
a.methodA();
a.methodB();
a.methodA();
}
}
Aspect intercepting method execution:
This aspect intercepts all method executions (not calls!) in your own code.
package de.scrum_master.aspect;
public aspect MyAspect {
after() : execution(* *(..)) {
System.out.println(thisJoinPoint);
}
}
The log output is:
MethodA
execution(void de.scrum_master.app.ClassA.methodA())
MethodA
execution(void de.scrum_master.app.ClassA.methodA())
MethodB
execution(void de.scrum_master.app.ClassA.methodB())
MethodA
execution(void de.scrum_master.app.ClassA.methodA())
execution(void de.scrum_master.app.Main.main(String[]))
Please note that also the execution of Main.main(..)
is being logged even though the method is never called explicitly (but executed nevertheless!).
Aspect intercepting method execution:
This aspect intercepts all method calls from your own code, which also includes calls to third-party or JDK classes.
Please note that in order to avoid an endless loop we have to add && !within(MyAspect)
because the aspect advice also calls a JDK method.
package de.scrum_master.aspect;
public aspect MyAspect {
after() : call(* *(..)) && !within(MyAspect) {
System.out.println(thisJoinPoint);
}
}
The log output in this case is:
MethodA
call(void java.io.PrintStream.println(String))
call(void de.scrum_master.app.ClassA.methodA())
MethodA
call(void java.io.PrintStream.println(String))
call(void de.scrum_master.app.ClassA.methodA())
MethodB
call(void java.io.PrintStream.println(String))
call(void de.scrum_master.app.ClassA.methodB())
MethodA
call(void java.io.PrintStream.println(String))
call(void de.scrum_master.app.ClassA.methodA())
Of course you could also use call()
and limit calls to your own packages, for example:
package de.scrum_master.aspect;
public aspect MyAspect {
after() : call(* de.scrum_master.app..*(..)) && !within(MyAspect) {
System.out.println(thisJoinPoint);
}
}
The log output here is:
MethodA
call(void de.scrum_master.app.ClassA.methodA())
MethodA
call(void de.scrum_master.app.ClassA.methodA())
MethodB
call(void de.scrum_master.app.ClassA.methodB())
MethodA
call(void de.scrum_master.app.ClassA.methodA())
It always depends on what you want to achieve.
If this is not what you wanted, please update your question to be more precise and notify me with a comment. Then I see what I can do.
Update concerning follow-up question about meta aspect:
package de.scrum_master.aspect;
public aspect MetaAspect {
before() : adviceexecution() && !within(MetaAspect) {
System.out.println(thisJoinPoint);
}
}
Log for first MyAspect
version using execution()
changes to:
MethodA
adviceexecution(void de.scrum_master.aspect.MyAspect.after(JoinPoint))
execution(void de.scrum_master.app.ClassA.methodA())
MethodA
adviceexecution(void de.scrum_master.aspect.MyAspect.after(JoinPoint))
execution(void de.scrum_master.app.ClassA.methodA())
MethodB
adviceexecution(void de.scrum_master.aspect.MyAspect.after(JoinPoint))
execution(void de.scrum_master.app.ClassA.methodB())
MethodA
adviceexecution(void de.scrum_master.aspect.MyAspect.after(JoinPoint))
execution(void de.scrum_master.app.ClassA.methodA())
adviceexecution(void de.scrum_master.aspect.MyAspect.after(JoinPoint))
execution(void de.scrum_master.app.Main.main(String[]))