How to remove java..* calls while using cflow() in aspectj?

限于喜欢 提交于 2019-12-10 20:47:16

问题


I have captured my problem in the following sample code. HelloWorld class is my source which needs to be instrumented by HelloWorldTracer aspect. My objective is to find all the method calls which are in the control flow of HelloWorld.main(). But I'm not interested in the method calls related to any types in the package java.lang.* (eg: java.lang.StringBuilder).

package com.abc;

public class HelloWorld {

    public static void main(String args[]) {
        StringBuilder str = new StringBuilder();
        str.toString();
        Sample.testMethod();
    }
}

package com.abc;

public class Sample {

    public static void testMethod()
    {
        StringBuilder str = new StringBuilder();
        str.toString(); 
    }

}


public aspect HelloWorldTracer {

    pointcut helloWorldTracker() : 
        execution(* com.sybase.HelloWorld.main(..)) && within(com.abc..*) &&  !within(HelloWorldTracer);

    pointcut methodTracker():
         cflow(helloWorldTracker()) 
         && !within(java.lang..*) && !within(HelloWorldTracer);

    Object around(): methodTracker()
    {

        System.out.println("Inside advice..." + thisJoinPointStaticPart.getSignature().toString() );
        Object o = proceed();
        return o;
    }

}

Using the poincuts mentioned above the type StringBuilder is also getting advised even though !within(java.lang..*) has been explicitly specified in methodTracker() pointcut. I also tried !within(java.lang.StringBuilder) and !execution(String java.langStringBuilder.toString(..)) as well, but in vain. Any help in restricting the types from java.lang..* from getting advised will be appreciated.


回答1:


Nitzan Volman's suggestion is not what you want.

First of all, in your code sample probably you want to change

execution(* com.sybase.HelloWorld.main(..))

to

execution(* com.abc.HelloWorld.main(..))

Having fixed that, you will get a lot of warnings because you are trying to advise initialization() and preinitialization() pointcuts with around() which is impossible due to compiler limitations.

Then when you change your output line to just

System.out.println(thisJoinPointStaticPart);

You will see what really happens in your code:

execution(void com.abc.HelloWorld.main(String[]))
call(java.lang.StringBuilder())
call(String java.lang.StringBuilder.toString())
call(void com.abc.Sample.testMethod())
staticinitialization(com.abc.Sample.<clinit>)
execution(void com.abc.Sample.testMethod())
call(java.lang.StringBuilder())
call(String java.lang.StringBuilder.toString())

I.e. you are not just intercepting method calls (or did you mean to catch method executions, which is not the same?), but all (well, many) sorts of joinpoints. Try this:

public aspect HelloWorldTracer {
    pointcut belowHelloWorldMain() :
        cflow(execution(* com.abc.HelloWorld.main(..)));

    pointcut methodTracker():
        belowHelloWorldMain() &&
        call(* *(..)) &&
        !call(* java.lang..*(..)) &&
        !within(HelloWorldTracer);

    Object around(): methodTracker() {
        System.out.println(thisJoinPointStaticPart);
        return proceed();
    }
}

Result:

call(void com.abc.Sample.testMethod())

Just in case you only wanted to intercept executions of (instead of calls to) your own (woven) classes anyway, it is even simpler, because then you do not need to exclude the Java classes:

public aspect HelloWorldTracer {
    pointcut belowHelloWorldMain() :
        cflow(execution(* com.abc.HelloWorld.main(..)));

    pointcut methodTracker():
        belowHelloWorldMain() &&
        execution(* *(..));

    Object around(): methodTracker() {
        System.out.println(thisJoinPointStaticPart);
        return proceed();
    }
}

Result:

execution(void com.abc.HelloWorld.main(String[]))
execution(void com.abc.Sample.testMethod())

As you can see, now even main(..) is included.




回答2:


I think you should use execution instead of within for this case.

pointcut methodTracker():
     cflow(helloWorldTracker()) 
     && !execution(* java.lang..*(..)) && !within(HelloWorldTracer);

methodTracker() captures all calls done from not within java.lang.*

The call to StringBuilder.toString() was done from Sample.testMethod() is therefor returned by the pointcut.



来源:https://stackoverflow.com/questions/7808700/how-to-remove-java-calls-while-using-cflow-in-aspectj

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!