在 Java 注释处理器中发现方法调用的类 [英] Discover the class of a methodinvocation in the Annotation Processor for java

查看:29
本文介绍了在 Java 注释处理器中发现方法调用的类的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I am writing some tools for our build system to enforce some strict calling conventions on methods belonging to classes containing certain annotations.

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

I'm using the Compiler Tree API...

我想知道的是,在遍历树"时,如何判断 MethodInvocation 的类/接口类型.

What i'm wondering is when traversing the 'tree', how can you tell the type of class/interface for a MethodInvocation.

我正在继承 TreePathScanner :

I'm subclassing TreePathScanner with :

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

}

我希望有一种方法可以告诉您尝试调用该方法的类(或接口)的类型.我会以错误的方式解决这个问题吗?感谢您的任何想法...

I'm hoping theres a way to tell the type of the class(or interface) that you're trying to invoke the method on. Am I going about this the wrong way? Thanks for any ideas...

推荐答案

这里有几个问题.你可以感兴趣知道方法调用接收者的 Java 类型或只是知道方法上的类被调用.Java资料较多信息丰富,因为它也为您提供通用类型,例如列表<字符串>而 Elements 只会为您提供课程,例如列表.

There are a couple of issues here. You can either be interested in knowing the Java type of the method invocation receiver or just knowing the class on the method is invoked. Java information is more informative as it gives you generic types as well, e.g. List<String> while Elements would only provide you with the class, e.g. List<E>.

获取元素

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

To get the Element of the class the method is invoked on, you can do the following:


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

角落案例:

1.调用类可能是接收器类型的超类.所以跑步new ArrayList.equals(null) 上的代码段将返回AbstractList 而不是 ArrayList,因为实现了 equals()在 AbstractList 不是 ArrayList.

1. invokedClass might be a superclass of the receiver type. So running the snippet on new ArrayList<String>.equals(null) would return AbstractList rather than ArrayList, since equals() is implemented in AbstractList not ArrayList.

2.处理数组调用时,例如new int[].clone(),你会获取 Array 类的 TypeElement.

2. When handling array invocations, e.g. new int[].clone(), you would get TypeElement of class Array.

获取实际类型

要获得类型,没有直接的方法来确定它是什么接收器类型是.处理方法调用有些复杂在没有明确给出接收者的内部类中(例如,与 OuterClass.this.toString() 不同).这是一个示例实现:

To get the type, there is no direct way for determining it what the receiver type is. There is some complexity in handling method invocations within inner classes where the receiver is not given explicitly (e.g. unlike OuterClass.this.toString()). Here is a sample implementation:


  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,比之前的信息量更大方法.

The receiver type needs to be TypeMirror not DeclaredType unfortunately. When calling new int[5].clone(), receiver would be an ArrayType of int[], which is more informative than the previous method.

让它运行

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

Both of the previous methods require the compiler to resolve the type information for the classes. In usual circumstances, the compiler only resolve the types for method declarations but not the bodies. Hence, the methods described earlier would return null instead.

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

To have the compiler resolve the type information, you can do one of the following ways:

1.使用刚刚添加到的 AbstractTypeProcessor 类JDK 7 的编译器存储库.查看关于 JSR 的工作308 和他们的编译器.虽然这项工作主要针对带注释的类型,但它可能对以下方面有用.编译器允许您反向使用提供的类与 Java 5 兼容.

1. Use AbstractTypeProcessor class that just got added to the compiler repository for JDK 7. Check out the work on JSR 308 and their compiler. While the work is mainly on annotated types, it might be useful for. The compiler allows you to use the provided class in a backward compatible manner with Java 5.

这种方法允许您编写仅被调用的处理器就像您当前的处理器一样.

This approach allows you to write processors that get invoked just like your current processors.

2.改用 JavacTask 并调用 JavacTask.analyze().看着这个javac测试看看如何在课程中调用您的访问者.

2. Use JavacTask instead and call JavacTask.analyze(). Look at the main method of this javac test to see how to invoke your visitor on the classes.

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

This approach makes your processor look more like an analysis tool rather than a plug-in to the compiler, as you would need to invoke it directly rather than have it be a regular process.

这篇关于在 Java 注释处理器中发现方法调用的类的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆