在java的Annotation Processor中发现methodinvocation的类

时间:2009-06-30 23:13:27

标签: java annotations preprocessor javac

我正在为构建系统编写一些工具,以对属于包含某些注释的类的方法强制执行一些严格的调用约定。

我正在使用编译器树API ...

我想知道的是,当遍历'tree'时,你怎么能告诉MethodInvocation的类/接口的类型。

我将TreePathScanner继承为:

@Override
public Object visitMethodInvocation(MethodInvocationTree node, Trees trees) {

}

我希望有一种方法可以告诉您尝试调用该方法的类(或接口)的类型。我是以错误的方式来做这件事的吗?谢谢你的任何想法...

1 个答案:

答案 0 :(得分:10)

这里有几个问题。你可能感兴趣 知道方法调用接收器的Java类型或只是 知道该方法的类被调用。 Java信息更多 提供信息,因为它也为您提供了通用类型,例如: List<String> 而Elements只会为您提供课程,例如List<E>

获取元素

要获取调用该方法的类的元素,您可以执行此操作 以下内容:


  MethodInvocationTree node = ...;
  Element method =
        TreeInfo.symbol((JCTree)node.getMethodSelect());
  TypeElement invokedClass = (TypeElement)method.getEnclosingElement();

转角案例:

1。 invokedClass可能是接收器类型的超类。好跑 new ArrayList<String>.equals(null)上的代码段会返回 AbstractList而不是ArrayList,因为实现了equals() 在AbstractList而非ArrayList

2。 处理数组调用时,例如new int[].clone(),你愿意 获得TypeElement课程的Array

获取实际类型

要获得类型,没有直接的方法来确定它是什么 接收器类型是。处理方法调用有一些复杂性 在没有明确给出接收器的内部类中 (例如,不像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即可 ArrayType的{​​{1}},比之前的信息更丰富 方法

让它运行

以前的两种方法都需要编译器来解析类型 课程的信息。在通常的情况下,编译器 只解析方法声明的类型而不解析主体。 因此,前面描述的方法将返回int[]

要让编译器解析类型信息,您可以执行以下操作之一 以下方式:

1。 使用刚刚添加到的null类 JDK 7的编译器存储库。查看JSR 308及其编译器的工作。 虽然工作主要是注释类型,但它可能是有用的。 编译器允许您在向后使用提供的类 与Java 5兼容的方式。

这种方法允许您编写仅被调用的处理器 就像你现在的处理器一样。

2。 请改用AbstractTypeProcessor并致电JavacTask。看着 this javac test的主要方法,看看如何 在课堂上调用你的访客。

这种方法使您的处理器看起来更像分析工具 而不是编译器的插件,因为您需要调用它 直接而不是让它成为常规过程。