Search code examples
annotationsaopaspectjaspectpointcut

AspectJ - pointcut advice based on annotated function


I have 2 custom annotations:

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
public @interface FlowPoint {
    public enum PointInFlow {
        START, END
    }
    PointInFlow pointInFlow();
}

and:

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
public @interface ScopeAnnotation {
    public enum Category {
        BUSINESS, DETECTION, INTERNAL_FUNC, THRESHOLD
    }
    Category category() default Category.DETECTION;
}

At my code I annotated a method with PointInFlow.START and some others with Category.DETECTION and Category.BUSINESS

my pointCuts are:

@Pointcut("execution(* *(..)) && @annotation(flowPoint) && if()")
public static boolean executeStartMethod(<annotationPackage>.FlowPoint flowPoint) {
        return flowPoint.pointInFlow() == FlowPoint.PointInFlow.START;}

@Before("executeStartMethod(flowPoint)")
public void beforeStartMethod(<annotationPackage>.FlowPoint flowPoint, JoinPoint jp) {
        logger.infoBefore(jp, flowPoint.pointInFlow());}

@After("executeStartMethod(flowPoint)")
public void afterStartMethod(<annotationPackage>.annotation.FlowPoint flowPoint, JoinPoint jp) {
        logger.infoAfter(jp);}


@Pointcut("execution(* *(..)) && @annotation(scopeAnnotation) && if()")
public static boolean executeDetectionMethod(<annotationPackage>.ScopeAnnotation scopeAnnotation) {
        return scopeAnnotation.category() == ScopeAnnotation.Category.DETECTION;}

@Before("executeDetectionMethod(scopeAnnotation)")
public void beforeDetectionMethod(<annotationPackage>.ScopeAnnotation scopeAnnotation, JoinPoint jp) {
        logger.infoBefore(jp, scopeAnnotation.category());}

@After("executeDetectionMethod(scopeAnnotation)")
public void afterDetectionMethod(<annotationPackage>.ScopeAnnotation scopeAnnotation, JoinPoint jp) {
        logger.infoAfter(jp);}


@Pointcut("execution(* *(..)) && @annotation(scopeAnnotation) && if()")
public static boolean executeBusinessMethod(<annotationPackage>.ScopeAnnotation scopeAnnotation) {
        return scopeAnnotation.category() == ScopeAnnotation.Category.BUSINESS;}

@Before("executeBusinessMethod(scopeAnnotation)")
public void beforeBusinessMethod(<annotationPackage>.ScopeAnnotation scopeAnnotation, JoinPoint jp) {
        logger.infoBefore(jp, scopeAnnotation.category());}

@After("executeBusinessMethod(scopeAnnotation)")
public void afterBusinessMethod(<annotationPackage>.annotation.ScopeAnnotation scopeAnnotation, JoinPoint jp) {
        logger.infoAfter(jp);}

The issue is DETECTION and BUSINESS separately are working, (when I comment out one of the detection or business pointcut definition.) but not as above together.

thanks in advance for any help


Solution

  • You should see the following AspectJ compile error:

    circular advice precedence:
      can't determine precedence between two or more pieces of advice that apply to the same join point:
      method-execution(void de.scrum_master.app.Application.doEight())
    

    As a work-around you can do this:

    @Pointcut("execution(* *(..)) && @annotation(scopeAnnotation) && if()")
    public static boolean executeDetectionOrBusinessMethod(ScopeAnnotation scopeAnnotation) {
      return
        scopeAnnotation.category() == ScopeAnnotation.Category.DETECTION ||
        scopeAnnotation.category() == ScopeAnnotation.Category.BUSINESS;
    }
    
    @Before("executeDetectionOrBusinessMethod(scopeAnnotation)")
    public void beforeDetectionOrBusinessMethod(ScopeAnnotation scopeAnnotation, JoinPoint jp) {
      infoBefore(jp, scopeAnnotation.category());
    }
    
    @After("executeDetectionOrBusinessMethod(scopeAnnotation)")
    public void afterDetectionOrBusinessMethod(ScopeAnnotation scopeAnnotation, JoinPoint jp) {
      infoAfter(jp);
    }
    

    Or if you insist in separating the pointcuts and advices for both annotation values, just use around advices instead of before/after:

    @Pointcut("execution(* *(..)) && @annotation(scopeAnnotation) && if()")
    public static boolean executeDetectionMethod(ScopeAnnotation scopeAnnotation) {
      return scopeAnnotation.category() == ScopeAnnotation.Category.DETECTION;
    }
    
    @Around("executeDetectionMethod(scopeAnnotation)")
    public Object aroundDetectionMethod(ScopeAnnotation scopeAnnotation, ProceedingJoinPoint jp) throws Throwable {
      infoBefore(jp, scopeAnnotation.category());
      try {
        return jp.proceed();
      } finally {
        infoAfter(jp);
      }
    }
    
    @Pointcut("execution(* *(..)) && @annotation(scopeAnnotation) && if()")
    public static boolean executeBusinessMethod(ScopeAnnotation scopeAnnotation) {
      return scopeAnnotation.category() == ScopeAnnotation.Category.BUSINESS;
    }
    
    @Around("executeBusinessMethod(scopeAnnotation)")
    public Object aroundBusinessMethod(ScopeAnnotation scopeAnnotation, ProceedingJoinPoint jp) throws Throwable {
      infoBefore(jp, scopeAnnotation.category());
      try {
        return jp.proceed();
      } finally {
        infoAfter(jp);
      }
    }