Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
290 views
in Technique[技术] by (71.8m points)

java - Java8, how discover the class and method name in visitMethodInvocation?

With Java7 and Java8, I would like to generate a warning if some methods was called. The warning will be print if a specific jar is present when then user compile.

I write an Annotation Processor and catch the visitMethodInvocation(). Now, I want extract the class and method names will be invoked.

Is it possible to do that ? Or how to approach this?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

You can do something like:

package mystuff;

import com.sun.source.tree.*;
import com.sun.source.util.*;
import java.util.*;
import javax.annotation.processing.*;
import javax.lang.model.element.*;
import javax.tools.*;

@SupportedAnnotationTypes("*")
    public class Proc extends AbstractProcessor{
    @Override
        public boolean process(Set<?extends TypeElement>annotations,RoundEnvironment roundEnvironment){
        final Trees trees=Trees.instance(processingEnv);
        for(Element element:roundEnvironment.getRootElements()){
        TreePath path=trees.getPath(element);
        final CompilationUnitTree compilationUnit=path.getCompilationUnit();
        compilationUnit.accept(new TreeScanner<Object,Object>(){
            @Override
                public Object visitMethodInvocation(MethodInvocationTree tree,Object data){
                tree.getMethodSelect().accept(new SimpleTreeVisitor<Object,Object>(){
                    @Override
                    public Object visitMemberSelect(MemberSelectTree tree,Object data){
                    processingEnv.getMessager().printMessage(Diagnostic.Kind.NOTE,String.format("class:  %1$s
method: %2$s",tree.getExpression(),tree.getIdentifier()));
                    return null;
                    }
                },null);
                return null;
            }
            },null);
        }
        return true;
    }
    }

I used that processor to process the below class

package stuff;

import java.util.*;

@MyAnnotation
class MyProgram{
    public void run(){
    System.out.println("Hello World!");
    }
}

and achieved this result:

class:  System.out
  method: println

I am pretty sure that the method name generated is what you are looking for. I am pretty sure that the "class" is not exactly what you are looking for, but is a pretty good start.

In my example you probably wanted it to print "java.io.PrintStream" for the class. To get that you could use processingEnv.getElementUtils().getTypeElement("java.lang.System") to get a TypeElement representing the system class. Then you can use processingEnv.getElementUtils().getAllMembers() to get every single member of the system class. Iterate through that to find out. Use the asType method to get its type.

The preceding paragraph was a gross simplification. The processor did not know a priori that out is a static member of a class that is part of the implicitly imported java.lang package. So your code will have to try and fail to find the following classes System and java.util.System (because it is in the imports), System.out, java.util.System.out, and java.lang.System.out.

I only dealt with MemberSelect. You will have to deal with other possibilities including MethodInvocation. For example new Object().toString().hashCode() should be class=Object, method=hashCode.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...