首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Java静态元编程

Java静态元编程
EN

Stack Overflow用户
提问于 2011-12-05 23:17:19
回答 3查看 2.5K关注 0票数 6

我想实现注释处理器,它将基于现有的“原型”类生成新的类。

代码语言:javascript
复制
import java.util.List

@MyAnnotation
class MySuperClassPrototype {
    static MySuperClassPrototype createInstance() {
      return new MySuperClassPrototype();
    }
}

作为以下代码的结果。将生成以下新的源文件(编译单元):

代码语言:javascript
复制
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方法,我会得到很好的结果,但是构造函数被打印成带有"“名称的方法,而不是与它的类同名的方法,所以我需要手动打印每种树节点。

你可以看到code I've come with here

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 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注释处理“。有很多很好的资源,它们会对你有所帮助。更重要的是,在这里列出。只需注意,注释处理器中编码与正常编码不同。差别不大,但是你正在处理的类还没有被创建。所以请记住这一点,不要灰心!

使用注释处理器

您的基本批注处理器将如下所示:

代码语言:javascript
复制
@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一样古老,但仍未得到广泛使用。我鼓励读者亲自尝试一下:)

票数 1
EN

Stack Overflow用户

发布于 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作为参考。

票数 6
EN

Stack Overflow用户

发布于 2017-04-28 10:32:27

看看https://github.com/rzwitserloot/lombok/,它添加了您所描述的方法。比如

getter

  • @getter添加基于fields

  • @Setter

  • @ToString的getter方法添加基于字段

toString()方法

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/8387506

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档