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
- a
ProoceedingJoinPoint
method parameter instead of a simple JoinPoint
,
- to explicitly call the joinpoint's
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.
- to return
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:
- Please follow Java coding guidelines and do not start class or aspect names with lower-case letters.
- Specifically do not use a class name
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.
- When you print an object like
System.out.println(jp.getTarget().toString())
, the toString()
is superfluous because this method will always be called implicitly when printing objects.
- When you have multiple aspects targeting the same joinpoints and wish to enforce a specific order in which they are called, learn how to use
@DeclarePrecedence
.
- I recommend to get rid of separate
@Pointcut
definitions and define your pointcuts inline unless you wish to re-use a pointcut.
- If you want to know what is going on in AspectJ, why not print the full joinpoint instead of "a method was called"? It helps understand what is going on tremendously.
- Learn the semantic difference between
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.
- Try to avoid putting your classes and aspects into the default package. This is not good style. Also you will notice that AspectJ pointcuts can be quite sensitive to package names.
- Instead of combining
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