@AspectJ Class level Annotation Advice with Annotation as method argument

aop, aspectj, java

Solution

The solution is actually quite simple. I am writing my code in native AspectJ style, I prefer it for clarity. You will be easily able to adjust it to @AspectJ annotation style:

public aspect LogTimeAspect {
    pointcut publicMethod() : execution(public * *(..));

    before(LogExecutionTime logAnn) : publicMethod() && @annotation(logAnn) {
        System.out.println(thisJoinPointStaticPart + " -> " + logAnn.level());
    }

    before(LogExecutionTime logAnn) : publicMethod() && @within(logAnn) {
        System.out.println(thisJoinPointStaticPart + " -> " + logAnn.level());
    }
}

The output is as follows:

execution(void Operator.operate()) -> Method_Level_Invocation
execution(void Operator.operate()) -> Class_Level_Invocation
execution(void Operator.operate1()) -> Class_Level_Invocation

As you can see,

- there is no need for `around()` advice, `before()` is sufficient unless you want to manipulate any parameters or block the captured method executions,

- you can bind the annotations in question via `@annotation()` or `@within()` to named parameters if you just use the correct syntax.

Enjoy! `:-)`

Update: Here is the @AspectJ version of the aspect for your convenience and because you seemed to have problems adapting my solution from the native syntax:

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;

@Aspect
public class LogTimeAspect {
    @Pointcut("execution(public * *(..))")
    public void publicMethod() {}

    @Around("publicMethod() && @annotation(logAnn)")
    public Object LogExecutionTimeByMethod(ProceedingJoinPoint joinPoint, LogExecutionTime logAnn) throws Throwable {
        System.out.println(joinPoint + " -> " + logAnn.level());
        return joinPoint.proceed();
    }

    @Around("publicMethod() && @within(logAnn)")
    public Object LogExecutionTimeByClass(ProceedingJoinPoint joinPoint, LogExecutionTime logAnn) throws Throwable {
        System.out.println(joinPoint + " -> " + logAnn.level());
        return joinPoint.proceed();
    }
}

The results will be identical to my original version.

Problem

How can I get the annotation to be passed as the argument for the Advice defined for class-level annotation? Is it possible? From the post here I am able to get the point cut that identifies all the public method in the class which is marked by a specific Annotation. I am able to get the advice applied as well. However, I don’t know how to get the annotation variable passed as argument in above case. For a method-level annotation, I am able to get the pointcut and advice in which I can get the annotation passed as argument, but I don’t know how to achieve the same for class-level annotation. The below code works, but I need to get the annotation as the argument for the advice “LogExecutionTimeByClass” in below program and I couldn’t able to get appropriate advice or pointcut for the same. Annotation: ``` import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; @Target({ElementType.TYPE, ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) public @interface LogExecutionTime { String level(); } ``` Aspect: ``` import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.Around; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Pointcut; @Aspect public class LogTimeAspect { /* * Pointcut to match all the public methods. */ @Pointcut("execution(public * *(..))") public void publicMethod() {} /* * Advice for the public methods that are marked with Annotation "LogExecutionTime" and it works as expected no issue. */ @Around("publicMethod() && @annotation(annotation) ") public Object LogExecutionTimeByMethod(final ProceedingJoinPoint joinPoint,final LogExecutionTime annotation) throws Throwable { System.out.println("Invoking the method " +joinPoint.getSignature() +" by LogExecutionTimeByMethod Advice"); return joinPoint.proceed(); } /* * Pointcut to match all the public methods that are defined under the Class marked with Annotation LogExecutionTime. */ @Pointcut("within(@LogExecutionTime *)") public void beanAnnotatedWithMonitor() {} @Pointcut("publicMethod() && beanAnnotatedWithMonitor()") public void publicMethodInsideAClassMarkedWithAtMonitor() {} /* * Below Advice works but I need the LogExecutionTime annotation as an argument to below method. (similar to the advice "LogExecutionTimeByMethod" * defined above) */ @Around("publicMethodInsideAClassMarkedWithAtMonitor()") public Object LogExecutionTimeByClass(final ProceedingJoinPoint joinPoint) throws Throwable { System.out.println("Invoking the method " +joinPoint.getSignature() +" by LogExecutionTimeByClass Advice"); //System.out.println("Invoked by " + annotation.value()); //Need the Annotation Variable here as well... return joinPoint.proceed(); } /* */ } ``` Annotated Class: ``` @LogExecutionTime(level="Class_Level_Invocation") public class Operator { @LogExecutionTime(level="Method_Level_Invocation") public void operate() throws InterruptedException { Thread.sleep(1000); } public void operate1() throws InterruptedException { Thread.sleep(1000); } } ``` Main Program: ``` public class AspectJMain { public static void main(String[] args) throws InterruptedException { Operator op = new Operator(); op.operate(); op.operate1(); } } ``` Output: ``` Invoking the method void Operator.operate() by LogExecutionTimeByMethod Advice Invoking the method void Operator.operate() by LogExecutionTimeByClass Advice Invoking the method void Operator.operate1() by LogExecutionTimeByClass Advice ``` Please note that using Spring is is not an option. I have to use AspectJ compiler. I compiled my classes and packaged them as jar and use ApsectJ compiler to woven the aspect using below command. ajc -inpath core.jar -outjar ..\lib\core_woven.jar -1.5 Any pointer would be helpful.

Original source

Related problems