我想实现注释处理器,它将基于现有的“原型”类生成新的类。
import java.util.List
@MyAnnotation
class MySuperClassPrototype {
static MySuperClassPrototype createInstance() {
return new MySuperClassPrototype();
}
}作为以下代码的结果。将生成以下新的源文件(编译单元):
import java.util.List
class MySuperClass {
static MySuperClass createInstance() {
return new MySuperClass();
}
public void specialAddedMethod() {
/*...*/
}
}我希望复制prototype-class的所有顶级import语句和静态成员,而不是静态成员。我已经在Compiler Tree API (com.sun.source.tree)方面取得了很大进展。我可以打印出Tree数据类型,同时用新的类名替换旧的类名。但是有一些问题似乎很难解决。
如果我在树中获得Tree.Kind.IDENTIFIER,我如何才能找到它引用的实际类。我需要用MySuperClass标识符替换所有出现的MySuperClassPrototype标识符,然后打印出整个树。
这可行吗?
类似地,我需要过滤掉@MyAnnotation注释,并再次使用Tree.Kind.IDENTIFIER或Tree.Kind.MEMBER_SELECT表示它。
我怎样才能找出这个标识符引用的实际注释类?
另一个问题是打印出树。如果我使用toString方法,我会得到很好的结果,但是构造函数被打印成带有"“名称的方法,而不是与它的类同名的方法,所以我需要手动打印每种树节点。
发布于 2019-08-25 18:42:24
8年了,还没有回答。正因为如此,我会试着回答这个问题,让你满意。
此外,我将重点放在问题的static部分。
TL;DR
在此答案中,您将找不到复制和粘贴代码。
它可行吗?
是的,完全正确。
如何才能找出该标识符引用的实际注释类?
您必须在批注处理器中使用RoundEnvironment来获取TypeElement。
静态元编程
静态元编程(您要求的)是在编译时完成的元编程。动态元编程是在运行时完成的元编程。元编程本身就是程序的设计,它将其他程序作为数据来处理。
天哪,有很多东西要接受。如果你对这个话题感兴趣,一个或多或少很好的资源是wikipedia。
您的目标是在编译时生成一个类。对于运行时,这可以使用类似cglib的东西来完成。但是,由于您选择了static (和for all the right reasons),我将不对此进行解释。
您正在寻找的概念是annotation processor。这个链接是到Baeldung的链接,他们在那里做你正在寻找的东西,只是考虑到了构建器模式。您一定会很高兴听到,这种场景非常受欢迎,而且使用批注处理器API也很容易实现。它甚至允许您生成代码,这些代码将再次传递给相同或另一个批注处理器,而无需执行任何操作。
在开始之前,试着用谷歌搜索一下"Java注释处理“。有很多很好的资源,它们会对你有所帮助。更重要的是,在这里列出。只需注意,注释处理器中编码与正常编码不同。差别不大,但是你正在处理的类还没有被创建。所以请记住这一点,不要灰心!
使用注释处理器
您的基本批注处理器将如下所示:
@SupportedAnnotationTypes("package.of.MyAnnotation")
@SupportedSourceVersion(SourceVersion.RELEASE_8)
@AutoService(Processor.class)
public class BuilderProcessor extends AbstractProcessor {
@Override
public boolean process(Set<? extends TypeElement> annotations,
RoundEnvironment roundEnv) {
// First let's find all annotated elements
Set<? extends Element> annotatedElements = roundEnv.getElementsAnnotatedWith(MyAnnotation.class);
// Handle all the annotated classes
return false;
}
}AutoService Annotation用于动态注册批注处理器。它来自外部来源,所以你不会奇怪,为什么这段代码不能编译。
在handle all annotated classes部件中,您拥有带注释的元素(即带注释的类)。您现在必须验证它们是否是类,而不是接口或其他注释。这是因为@Target(ElementType.Type)针对任何类型,包括接口和注释。此外,您可能希望验证所需的内容是否存在,或者使用Messager向编译器打印错误。
如果在这里打印错误(例如),您将停止编译,并且在大多数现代IDE中都会看到该错误。可以通过调用roundEnv.getMessager()来访问它
然后,您可以生成一个新类,并将其作为.java文件写入编译器的输入。这可以通过使用Filer来完成。
在StackOverflow中的回答确实不能很好地解决这个问题。I highly建议您查看Baeldung示例,并尝试从中发现一些问题。此API与Java 6一样古老,但仍未得到广泛使用。我鼓励读者亲自尝试一下:)
发布于 2011-12-05 23:34:42
是的,这是可能的,我至少知道两种方法。
首先,“传统”的方法是编写ant task/maven plugin/仅仅是命令行java实用工具,它扫描给定的文件路径并为每个类调用类似于Class.forName(className).getAnnotations(MyAnnotation.class)的东西。如果这不为空,则使用反射发现类并执行所需的操作。
其他方法稍微困难一点,但功能更强大。您可以实现自己的Processor (它实现了javax.annotation.processing.Processor,甚至更好地扩展了javax.annotation.processing.AbstractProcessor。您的处理器只需放在compiler类路径中,它将在编译器运行时自动运行。您甚至可以配置您的IDE (例如Eclipse)来运行您的处理器。它是对java编译器的一种扩展。因此,每次eclipse构建您的项目时,它都会运行处理器,并根据您添加的新注释创建所有新类。
请看一下这个project作为参考。
发布于 2017-04-28 10:32:27
看看https://github.com/rzwitserloot/lombok/,它添加了您所描述的方法。比如
getter
的toString()方法
https://stackoverflow.com/questions/8387506
复制相似问题