简体   繁体   中英

AspectJ - Pointcut at specified method with a param annotated with class level annotation

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) {}  

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM