提问人:zaaarf 提问时间:3/27/2023 更新时间:3/27/2023 访问量:77
如何在注解处理环境中找到一个匿名类?
How to find an anonymous class in the annotation processing environment?
问:
我正在用 Java 8 编写注释处理器。
假设我的项目中的某个地方有一个这样的类:
public class SampleClass {
public void foo(int i) {
new Runnable() {
@Override
public void run() {
System.out.println(i);
}
};
}
}
在我的代码的其他地方,我有我的注释,其中包含 SampleClass 的完全限定名称和在编译后标识匿名类的唯一整数(如 SampleClass$id 中)。
为了执行我的任务,我需要找到表示该特定匿名类的对象。或者,除此之外,至少获取表示某个类中匿名类的对象列表将是一个开始。我很确定这是可能的,因为在包的文档中多次引用了匿名类,但我不知在我的情况下如何具体地获得它们。javax.lang.model.element.Element
Element
javax.lang.model
我确实尝试了最明显的事情。假设我想编写一个方法,该方法给定一个类和一个对象 () 的完全限定名称 (),构建该元素中包含的所有匿名类的列表(以及递归地,它的每个子元素及其子元素,依此类推)。这是我对如何做到这一点的最佳猜测:fqn
ProcessingEnvironment
env
public List<Element> findAnonymousClasses(String fqn, ProcessingEnvironment env) {
Element sampleClassElement = processingEnvironment.getElementUtils().getTypeElement(fqn);
List<Element> anons = new ArrayList<>();
sampleClassElement.getEnclosedElements()
.forEach(e -> {
if(e.getSimpleName().length() == 0)
anons.add(e);
anons.addAll(getAnonymousClasses(e, env));
});
}
我的理由是,根据其文档:getSimpleName()
如果它表示匿名类或实例初始值设定项,则返回一个空名称。
和
空 {@code Name} 的长度为零。
该代码显然是有缺陷的,因为它也会返回类方法中的匿名类,但它至少应该返回一些东西!然而,显然,这是空的。替换为会产生相同的结果。List
e.getSimpleName().length() == 0
e instanceof TypeElement && ((TypeElement) e).getNestingKind() == NestingKind.ANONYMOUS
然而,进一步的检查表明,问题不在于我如何过滤它。相反,它似乎从不包含匿名类。那我怎样才能找到它们呢?当然,如果对它们进行了编码(即),它们必须以某种方式获得?希望这里的任何人都能在正确的方向上推动我。Element.getEnclosedElements()
NestingKind.ANONYMOUS
答:
为了执行我的任务,我需要找到表示该特定匿名类的 javax.lang.model.element.Element 对象。
它不存在。这是你的问题。
我有我的注释,其中包含 SampleClass 的完全限定名称和编译后标识匿名类的唯一整数(如 SampleClass$id 中)。
你说的那个名字()是二进制名称,并不真正适用于源代码。编译过程会经历多个阶段。进行注释处理的阶段早于以二进制形式处理名称的阶段。在注释处理器执行的阶段,无法引用匿名内部类。SampleClass$1
这相当深入。Javac 创建了一个“惰性”模型,即它只创建那些需要的节点。这显然排除了方法局部类型(匿名内部类是一种方法局部类型)。这不仅仅是“无法访问您拥有的给定信息” - TypeElement
实例在您想要访问它时甚至不存在。TypeElement
Javac 是一个复杂的项目,这些节点用于各种事情。因此,“嘿,有一个,当然这意味着只要我知道怎么做,所有匿名类都可以访问”的结论是行不通的,即使这确实是一个合理的结论。Kind.ANONYMOUS
通过黑客,您可以更深入地挖掘并打开内部结构,这可能会也可能不会让您做自己想做的事。这是火箭科学,需要几个月的工作才能写出来。我知道。(我共同维护龙目岛项目,它就是这样做的)。我怀疑你想这样做。javac
也许退后一步:你为什么需要这个?当然,你有一些想要解决的实际问题,并且你认为“我将使用 AP 来访问匿名内部类”是解决您想要解决的任何问题的一个很好的解决方案。
不幸的是,事实可能并非如此。但是,如果你问一个新问题(不要编辑这个问题——我认为从根本上改变问题的性质不是编辑的目的),陈述你试图解决的问题,也许有一个你不知道的替代解决方案会更合适。
评论