Reputation: 113
I have annotation:
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
public @interface Loggable { }
and aspect:
@Aspect
public class AspectLogger {
@Around("@annotation(aspects.Loggable)")
public void aroundLogging(ProceedingJoinPoint joinPoint) {
System.out.println("aroundLogging()");
throw new AuthentificationFailException();
}
}
Also I have interface and class:
public interface IAuthInteractor {
public User authorization(String login, String password);
}
public class AuthInteractor implements IAuthInteractor {
private EntityDAO<User> userDAO;
private ITokenGenerator tokenGenerator;
public AuthInteractor(EntityDAO<User> userDAO,
ITokenGenerator tokenGenerator) {
this.userDAO = userDAO;
this.tokenGenerator = tokenGenerator;
}
@Loggable
public User authorization1(String login, String password) {
return null;
}
@Loggable
public User authorization(String login, String password) {
return null;
}
}
For first method (authorization1) annotation doesn't work. For method authorization (that was described in interafce) annotation works.
Why does it work this way? and how to work without interface?
Upvotes: 0
Views: 1202
Reputation: 67317
First of all, the aspect's advice has a void
return type, i.e. it will never kick in for methods returning other types such as User
in your example. The aspect should not even compile. It does not for me in any case. The AspectJ compiler says:
applying to join point that doesn't return void: method-execution(de.scrum_master.app.User de.scrum_master.app.AuthInteractor.authorization(java.lang.String, java.lang.String))
So, assuming you change your advice to
@Around("@annotation(aspects.Loggable)")
public Object aroundLogging(ProceedingJoinPoint joinPoint) {
System.out.println("aroundLogging()");
throw new AuthentificationFailException();
}
it will compile and also kick in. I tested it locally.
Now let me just quickly change the advice to actually proceed to the original method instead of always throwing an exception so we can test a bit more without catching exceptions all the time. I also want to print the actual joinpoint signature, so we can see what is going on:
@Around("@annotation(aspects.Loggable)")
public Object aroundLogging(ProceedingJoinPoint joinPoint) throws Throwable {
System.out.println(joinPoint);
//throw new AuthentificationFailException();
return joinPoint.proceed();
}
If then you add this main
method to your interface implementation class:
public static void main(String[] args) {
System.out.println("Interface object");
IAuthInteractor iAuthInteractor = new AuthInteractor(null, null);
iAuthInteractor.authorization("user", "pw");
System.out.println("\nImplementation object");
AuthInteractor authInteractor = new AuthInteractor(null, null);
authInteractor.authorization("user", "pw");
authInteractor.authorization1("user", "pw");
}
The console log should print something like this, assuming you use AspectJ and not just "AOP lite" via Spring AOP which does not support call()
joinpoints:
Interface object
execution(User de.scrum_master.app.AuthInteractor.authorization(String, String))
Implementation object
call(User de.scrum_master.app.AuthInteractor.authorization(String, String))
execution(User de.scrum_master.app.AuthInteractor.authorization(String, String))
call(User de.scrum_master.app.AuthInteractor.authorization1(String, String))
execution(User de.scrum_master.app.AuthInteractor.authorization1(String, String))
As you can see, executions are always caught, but calls are not for interface type instances because the interface method is not annotated, only the implementation.
BTW, method annotations are not inherited anyway, so your @Inherited
meta annotation for an annotation type with @Target({ElementType.METHOD})
is kinda useless.
Upvotes: 1