Reputation: 31
In an aspect, i'd like stop at a specified method. This method has one parameter which is annotated with a class level annotation:
The annotation is:
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface Auditable {}
The parameter is an object of a class annotated like:
@Auditable
public class User {}
The method I like to inspect:
public Object findSingleResultByExample(final Object entity) {}
This aspect is not working:
@AfterReturning(value="execution(* org.wtp.repository.GenericDao.find*(@org.wtp.aspects.Auditable (*)))",
argNames = "joinPoint, result",
returning = "result")
private void auditFindAnnotation(final JoinPoint joinPoint, final Object result) {}
Upvotes: 1
Views: 570
Reputation: 67317
First of all, your advice method must be public
, not private
. Please change that into
public void auditFindAnnotation(...)
It is not working because your pointcut intercepts methods with an @Auditable
parameter annotation. Your sample method does not have such an annotation, though. It would work if the method signature was like this:
public Object findSingleResultByExample(final @Auditable Object entity) {}
BTW, then the @Target(ElementType.TYPE)
restriction must be removed or extended in order for the code to still compile.
But I guess what you want is not to match on parameter annotations, but on type annotations. Then your pointcut would look like this (no parentheses around *
this time):
execution(* org.wtp.repository.GenericDao.find*(@org.wtp.aspects.Auditable *))
But again, this does not match your sample method because its parameter type is not User
or Auditable
but just Object
and the latter does not carry the annotation. You can see the difference if you overload your find*
method and do something like this:
package de.scrum_master.app;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@Retention(RetentionPolicy.RUNTIME)
public @interface Auditable {}
package de.scrum_master.app;
@Auditable
public class User {}
package de.scrum_master.app;
import java.util.ArrayList;
public class Application {
public Object findSingleResultByExample(final Object entity) {
return entity;
}
public Object findSingleResultByExample(final User entity) {
return entity;
}
public static void main(String[] args) {
Application application = new Application();
application.findSingleResultByExample("foo");
application.findSingleResultByExample(new User());
application.findSingleResultByExample(new ArrayList<String>());
}
}
package de.scrum_master.aspect;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
@Aspect
public class AuditAspect {
@AfterReturning(
value = "execution(* de.scrum_master.app..find*(@de.scrum_master.app.Auditable *))",
argNames = "thisJoinPoint, result",
returning = "result"
)
public void auditFindAnnotation(final JoinPoint thisJoinPoint, final Object result) {
System.out.println(thisJoinPoint + " -> " + result);
}
}
The console log then looks like this:
execution(Object de.scrum_master.app.Application.findSingleResultByExample(User)) -> de.scrum_master.app.User@4a574795
Update: In order to get the whole thing working without changing or overloading any method signatures, you would have to make your pointcut match all calls and dynamically determine the type and its annotations from withing the aspect via reflection (not so nice, but possible). Feel free to ask questions if you do not understand this idea.
Upvotes: 1