2009-06-30 112 views
6

我正在为我们的构建系统编写一些工具来强制对属于包含某些注释的类的方法实施一些严格的调用约定。在java注释处理器中发现一个methodinvocation的类

我使用的编译器API树...

什么,我不知道遍历“树”时,你怎么能告诉类/接口的的MethodInvocation的类型。

我继承TreePathScanner有:

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

} 

我希望那里有一种方法来告诉你试图调用的方法的类(或接口)的类型。我是否以这种错误的方式去做?感谢您的任何想法...

回答

8

这里有几个问题。知道方法调用接收器的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,因为等于()被执行 在AbstractList而不是ArrayList

2. 当处理数组调用时,例如, new int[].clone(),你会 得到TypeElementArray

获取实际类型

要获得类型,一种用于确定它 接收器是什么类型的直接方式。在内部类中处理方法调用 存在一些复杂性,其中接收者没有明确给出 (例如,不像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类型必须TypeMirrorDeclaredType 不幸。当致电new int[5].clone()时,receiver将是 和的int[],其比以前的方法更具信息性。

得到它的运行

以前的方法都需要编译器解析类的 类型的信息。在通常情况下,编译器 仅解析方法声明的类型,但不解析主体。因此,之前描述的方法将返回null

可以让编译器解析类型的信息,你可以做一个 通过以下方式:即刚刚加入 编译器库的JDK 7,检查各项工作

1. 使用AbstractTypeProcessor类在JSR 308及其编译器上。 虽然工作主要在注释类型上,但它可能对您有用。 编译器允许你使用Java 5

使用提供的类在一个落后的 兼容的方式这种方法允许你写得到的只是 喜欢你目前的处理器调用处理器。

2. 改为使用JavacTask,并致电JavacTask.analyze()。请看 this javac test的主要方法,看看 如何调用你的访问者的类。

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

+0

谢谢你的回应。但是,行: 元素方法= TreeInfo.symbol(((JCTree)node.getMethodSelect()); 对我而言返回null。 \t TypeMirror m = trees.getTypeMirror(path); 也返回null,如同 \t TypeElement e =(TypeElement)trees.getElement(path); 我是否犯了一个菜鸟错误,忘记了初始化某些东西,或者调用/覆盖了错误的方法,或者将错误的子类化了?再次感谢您的帮助... – runT1ME 2009-07-01 00:27:34