在java的Annotation Processor中发现methodinvocation的类
我正在为构建系统编写一些工具,以对属于包含某些注释的类的方法强制执行一些严格的调用约定。
我正在使用编译器树API …
我想知道的是,当遍历’tree’时,你怎么能告诉MethodInvocation的类/接口的类型。
我将TreePathScanner子类化为:
@Override public Object visitMethodInvocation(MethodInvocationTree node, Trees trees) { }
我希望有一种方法可以告诉您尝试调用该方法的类(或接口)的类型。 我是以错误的方式来做这件事的吗? 谢谢你的任何想法……
这里有几个问题。 您可能有兴趣知道方法调用接收器的Java类型,或者只是知道调用该方法的类。 Java信息提供的信息更丰富,因为它也为您提供了generics类型,例如List
而Elements只为您提供类,例如List
。
获得元素
要获取调用该方法的类的元素,您可以执行以下操作:
MethodInvocationTree node = ...; Element method = TreeInfo.symbol((JCTree)node.getMethodSelect()); TypeElement invokedClass = (TypeElement)method.getEnclosingElement();
拐角案件:
1. invokedClass可能是接收器类型的超类。 因此,在new ArrayList
上运行代码段会返回AbstractList
而不是ArrayList
,因为equals()是在AbstractList
而不是ArrayList
。
2.在处理数组调用时,例如new int[].clone()
,您将得到类Array
TypeElement
。
获得实际类型
要获得类型,没有直接的方法来确定接收器类型是什么。 在内部类中处理方法调用存在一些复杂性,其中未明确给出接收器(例如,与OuterClass.this.toString()
不同)。 这是一个示例实现:
MethodInvocationTree node = ...; TypeMirror receiver; if (methodSel.getKind() == Tree.Kind.MEMBER_SELECT) { ExpressionTree receiver = ((MemberSelectTree)methodSel).getExpression(); receiverType = ((JCTree)receiver).type; } else if (methodSel.getKind() == Tree.Kind.IDENTIFIER) { // need to resolve implicit this, which is described in // JLS3 15.12.1 and 15.9.2 // A bit too much work that I don't want to work on now // Look at source code of // Attr.visitApply(JCMethodInvocation) // resolveImplicitThis(DiagnosticPosition, Env, Type) } else throw new AssertionError("Unexpected type: " + methodSel.getKind());
注意:
遗憾的是, receiver
类型必须是TypeMirror
而不是DeclaredType
。 当调用new int[5].clone()
, receiver
将是int[]
的ArrayType
,它比前一个方法更具信息性。
让它运行
以上两种方法都要求编译器解析类的类型信息。 在通常情况下,编译器仅解析方法声明的类型而不解析主体。 因此,前面描述的方法将返回null
。
要让编译器解析类型信息,您可以执行以下方法之一:
1.使用刚刚添加到JDK 7的编译器存储库的AbstractTypeProcessor
类。查看有关JSR 308及其编译器的工作。 虽然工作主要是注释类型,但它可能有用。 编译器允许您以与Java 5向后兼容的方式使用提供的类。
这种方法允许您编写像当前处理器一样调用的处理器。
2.改用JavacTask
并调用JavacTask.analyze()
。 查看此javac测试的主要方法,了解如何在类上调用访问者。
这种方法使您的处理器看起来更像分析工具,而不是编译器的插件,因为您需要直接调用它而不是将其作为常规进程。