对于Java7和Java8,我想在调用某些方法时生成警告。 如果用户编译时存在特定的jar,则会打印警告。
我编写了一个Annotation Processor并捕获了visitMethodInvocation()。现在,我想要解压缩类和方法名称将被调用。
有可能吗? 或者如何解决这个问题?
答案 0 :(得分:4)
您可以执行以下操作:
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\nmethod: %2$s",tree.getExpression(),tree.getIdentifier()));
return null;
}
},null);
return null;
}
},null);
}
return true;
}
}
我使用该处理器处理以下类
package stuff;
import java.util.*;
@MyAnnotation
class MyProgram{
public void run(){
System.out.println("Hello World!");
}
}
并取得了这个成果:
class: System.out
method: println
我很确定生成的方法名称是您正在寻找的。我很确定“课程”并不完全符合您的要求,但这是一个非常好的开始。
在我的示例中,您可能希望它为类打印“java.io.PrintStream”。为此,您可以使用processingEnv.getElementUtils().getTypeElement("java.lang.System")
来获取表示系统类的TypeElement。然后,您可以使用processingEnv.getElementUtils().getAllMembers()
来获取系统类的每个成员。迭代查找out
。使用asType
方法获取其类型。
前一段是粗略的简化。处理器不知道先验out
是隐式导入的java.lang
包的类的静态成员。因此,您的代码必须尝试并且无法找到以下类System
和java.util.System
(因为它在导入中),System.out
,java.util.System.out
和{{1 }}
我只处理了MemberSelect。您将不得不处理其他可能性,包括MethodInvocation。例如,java.lang.System.out
应为class = Object,method = hashCode。
答案 1 :(得分:3)
作为@emory的优秀答案的替代方案,您可以考虑使用the Checker Framework提供的可插入类型检查注释处理。它的优点是它可以帮助您轻松确定方法调用者的类型。这是一个基于checker框架的示例处理器(在编译时将checker.jar添加到类路径中)。
@SupportedAnnotationTypes("*")
@SupportedSourceVersion(SourceVersion.RELEASE_8)
public class MyTypeProcessor extends AbstractTypeProcessor {
class MyTreePathScanner extends TreePathScanner<Void, Void> {
private final Trees trees;
private final TreePath root;
public MyTreePathScanner(TreePath root) {
this.trees = Trees.instance(processingEnv);
this.root = root;
}
@Override
public Void visitMemberSelect(MemberSelectTree node, Void aVoid) {
ExpressionTree expression = node.getExpression();
TreePath expr = TreePath.getPath(root, expression);
TypeMirror type = trees.getTypeMirror(expr);
Element typeElement = processingEnv.getTypeUtils().asElement(type);
Optional<? extends Element> invoker = typeElement.getEnclosedElements().stream().filter(
e -> e.getSimpleName().equals(node.getIdentifier())).findFirst();
if (invoker.isPresent() && invoker.get().getKind() == ElementKind.METHOD) {
System.out.println("Type: " + typeElement + ", method: " + invoker.get());
}
return super.visitMemberSelect(node, aVoid);
}
}
@Override
public void typeProcess(TypeElement typeElement, TreePath root) {
new MyTreePathScanner(root).scan(root, null);
}
}
正在处理以下输入源。
public class Test {
public void foo() {
}
public static void main(String[] args) {
System.out.println("Hello world!");
Test t = new Test();
t.foo();
}
}
这是输出:
Type: java.io.PrintStream, method: println()
Type: Test, method: foo()