Hei, I started learning Aspectj and I have built 2 aspects. Both aspects have a pointcut that match the same function, and both aspects have an around advice that will do something on that pointcut. However only one advice will be "executed", and I do not understand why.
let me show you:
@Aspect
public class secondAspect {
@Pointcut("call( * main.*(..))")
public void pointCutThatMatchesEveryFunctionFromMain(){
}
@Around("pointCutThatMatchesEveryFunctionFromMain()")
public void adviceOnPointCutThatMatchesEveryFunctionFromMain(JoinPoint jp){
System.out.println("A method was called");
System.out.println(jp.getTarget().toString());
}
}
that is the second aspect
@Aspect
public class firstAspect {
@Pointcut("call( public * main.*(..)) && args(x,y)")
public void pointCutOnMainClassIntArgs(int x, int y) {
}
@Pointcut("call( public * main.*(..)) && args(x,y)")
public void pointCutOnMainClassFloatArgs(float x, float y) {
}
@Around("pointCutOnMainClassIntArgs(x,y)")
public void doSomethingOnThisPointCut(JoinPoint pjp, int x, int y) {
System.out.println(String.format("The method name is %s and was called with parameteres %d %d", pjp.getTarget().toString(), x, y));
}
@Around("pointCutOnMainClassFloatArgs(x,y)")
public void doSomethingOnThisPointCutWithFloatArgs(JoinPoint pjp, float x, float y) {
System.out.println(String.format("The method name is %s and was called with parameteres %f %f", pjp.getTarget().toString(), x, y));
}
}
the first aspect
public class main {
public static void main(String[] args) {
main maine = new main();
maine.calculate(2,3);
maine.calculate(2.0f,5.0f);
}
public void calculate(int x, int y){
System.out.println(x+y);
}
public void calculate(float x, float y){
System.out.println(x+y);
}
}
and this is the class that i want to modify. Only the secondAspect's adivce is executed. And I don't get it why.
The short answer is: Change your advice type from @Around
to @Before
, then it works and the console output will turn into:
A method was called
main@5f341870
The method name is main@5f341870 and was called with parameteres 2 3
The method name is main@5f341870 and was called with parameteres 2,000000 3,000000
5
A method was called
main@5f341870
The method name is main@5f341870 and was called with parameteres 2,000000 5,000000
7.0
Caveat: If you inspect the above log output, you will notice that your advice doSomethingOnThisPointCutWithFloatArgs
also matches the method with the int
parameters, which probably was not your intention. You need to be more precise than main.*(..)
and better use main.*(int, int)
vs. main.*(float, float)
in your pointcuts.
The long answer is: You should read an AspectJ tutorial. For example, an @Around
advice needs
ProoceedingJoinPoint
method parameter instead of a simple JoinPoint
,proceed()
method in order to actually call the intercepted target method. You did not do that, which is the explanation which only one random aspect (the first one found by AspectJ) was executed, but not the second because you designed your advice code in such a way that you never proceeded to the target method.Object
or a more specific non-void
type if you want to match methods returning something other than void
. You either need to return the result of proceed()
or something else you wish to be returned as the result of the target method.Some more suggestions:
main
, then a method main
and due to the naming clash a local variable maine
. I guess it does not get much uglier than that.System.out.println(jp.getTarget().toString())
, the toString()
is superfluous because this method will always be called implicitly when printing objects.@DeclarePrecedence
.@Pointcut
definitions and define your pointcuts inline unless you wish to re-use a pointcut.call()
and execution()
: While the former intercepts all callers (i.e. the sources of method calls), the latter intercepts the calls themselves no matter where they originate from. See here and the AspectJ manual for more information.PrintStream.println
and String.format
, just use PrintStream.printf
.How about this?
package de.scrum_master.app;
public class Application {
public static void main(String[] args) {
Application application = new Application();
application.calculate(2, 3);
application.calculate(2.0f, 5.0f);
}
public void calculate(int x, int y) {
System.out.println(x + y);
}
public void calculate(float x, float y) {
System.out.println(x + y);
}
}
package de.scrum_master.aspect;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
@Aspect
public class FirstAspect {
@Before("execution(public !static * *(int, int)) && args(x, y) && target(targetInstance)")
public void publicNonStaticMethodsWith2IntParameters(JoinPoint joinPoint, int x, int y, Object targetInstance) {
System.out.printf("[FA] %s -> %s [%s, %s]%n", joinPoint, targetInstance, x, y);
}
@Before("execution(public !static * *(float, float)) && args(x, y) && target(targetInstance)")
public void publicNonStaticMethodsWith2FloatParameters(JoinPoint joinPoint, float x, float y, Object targetInstance) {
System.out.printf("[FA] %s -> %s [%s, %s]%n", joinPoint, targetInstance, x, y);
}
}
package de.scrum_master.aspect;
import java.util.Arrays;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
@Aspect
public class SecondAspect {
@Before("execution(public !static * *(..)) && target(targetInstance)")
public void publicNonStaticMethods(JoinPoint joinPoint, Object targetInstance) {
System.out.printf("[SA] %s -> %s %s%n", joinPoint, targetInstance, Arrays.deepToString(joinPoint.getArgs()));
}
}
[FA] execution(void de.scrum_master.app.Application.calculate(int, int)) -> de.scrum_master.app.Application@6c3708b3 [2, 3]
[SA] execution(void de.scrum_master.app.Application.calculate(int, int)) -> de.scrum_master.app.Application@6c3708b3 [2, 3]
5
[SA] execution(void de.scrum_master.app.Application.calculate(float, float)) -> de.scrum_master.app.Application@6c3708b3 [2.0, 5.0]
[FA] execution(void de.scrum_master.app.Application.calculate(float, float)) -> de.scrum_master.app.Application@6c3708b3 [2.0, 5.0]
7.0