Question

I want to log entry to all methods from a list of classes (which could belong from different packages). Note that the methods should belong to the specified classes only.

I've tried the following but these do not work

(1) Using if() pointcut Here I get an error

"incompatible number of arguments to pointcut, expected 1 found 0"

@Pointcut("execution(*.*(..)) && if()")
public static boolean mycut(JoinPoint jp) {
     boolean matches = ... ;//Test using jp if the declaring class belongs to the list
     return matches;
}

(2) Using combination of Pointcut and aop.xml Here I get an error

java.lang.NoSuchMethodError:
com.mypackage.TraceAspect.aspectOf()Lcom/df/jc/aspect/TraceAspect;

//in com.mypackage.TraceAspect aspect class
@Pointcut("execution(*.*(..)) && !within(com.mypackage.TraceAspect)")
public void mycut(){
}

//in aop.xml
<weaver>
    <include within="package1.Class1">
    <include within="package2.Class2">
    <include within="package3.Class3">
</weaver>

What is going wrong here?

It can of course be done by specifying each class individually in the pointcut, but this is not scalable for hundreds of classes. Ideally, it would be great if the list of classes can be picked up from an external text file (for easy configuration)

Was it helpful?

Solution

As for your last comment: I am not discouraging you from anything but bad design, I was trying to encourage you to do the right thing: refactor and not make life harder on yourself than necessary. You do not even know the very AspectJ syntax basics and yet you already want to implement an over-complex scenario with tons of classes, which is a maintenance nightmare. I am trying to help by motivating you not to make short-sighted decisions. Believe me, I have been using AspectJ for years in what you call real-life projects with lots of legacy code. Avoiding even the cheapest bit of refactoring is much more expensive than doing smart refactoring - not too much, but enough according to the boy scout rule: leave the camp ground behind cleaner than you found it. It pays off, trust me.

Anyway, talking about your code snippet:

  • execution(*.*(..)) is syntactically wrong because you do not specify a return type (or placeholder for it) for the methods to be matched. You want to use execution(* *.*(..)) or the shorthand version execution(* *(..)).
  • The error "incompatible number of arguments to pointcut, expected 1 found 0" does not come from your pointcut but from your advice which you have not even bothered to post. You must have written something like @Before("mycut()"), but correct would be @Before("mycut(jp)").

Having said that, here is a simple, fully self-contained and compileable example:

Driver application:

package de.scrum_master.app;

public class Application {
    public static void main(String[] args) {
        System.out.println(multiply(3, add(4, 5)));
    }

    public static int multiply(int i, int j) { return i * j; }
    public static int add(int i, int j) { return i + j; }
}

Aspect:

package de.scrum_master.aspect;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;

@Aspect
public class TraceAspect {
    @Pointcut("execution(* *(..)) && if()")
    public static boolean hasMatchingSignature(JoinPoint thisJoinPoint) {
        return !thisJoinPoint.getSignature().getName().equals("main");
    }

    @Before("hasMatchingSignature(thisJoinPoint)")
    public void myAdvice(JoinPoint thisJoinPoint) {
        System.out.println(thisJoinPoint);
    }
}

Sample output:

execution(int de.scrum_master.app.Application.add(int, int))
execution(int de.scrum_master.app.Application.multiply(int, int))
27

If your if() pointcut would just return true, the output would also show the execution of main.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top