V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
asanelder
V2EX  ›  Java

Java annotation processor 拿到被注解文件的内容

  •  
  •   asanelder · 2020-06-01 21:45:35 +08:00 · 2448 次点击
    这是一个创建于 1628 天前的主题,其中的信息可能已经有所发展或是发生改变。

    有一个这样的注解

    @Target(ElementType.TYPE)
    @Retention(RetentionPolicy.SOURCE)
    public @interface Question {}
    

    被注解的文件如下

    @Question
    public class SomeQuestion {
    	public void foo(){}	
    }
    

    现在的问题是,我想在 annotation processor 中,拿到被注解文件的源代码,这里就是

    public class SomeQuestion {
    	public void foo(){}	
    }
    

    如何做到呢?求助!

    第 1 条附言  ·  2020-06-01 23:05:09 +08:00
    我的意思是,有没有相关的 annotation api 可以得到 source code. 比如说 TypeElement 就已经表示源文件中的一个类型结构了,按道理来说,通过 TypeElement 就可以得到它所表示的结构信息,也就是相关的 souce code,但我找了半天,好像没有。
    第 2 条附言  ·  2020-06-02 00:05:28 +08:00

    添加一个stackoverflow上的回答吧。以下

    Java's standard annotation processors provide a callback only at declarations, such as method and field declarations.

    It's possible to use an annotation processor to analyze expressions, but it's a bit more work. You will have to write an annotation processor that, at each method, obtains the AST (abstract syntax tree or parse tree) for the method and then visits each expression in the method. The AST is compiler-specific.

    The two best-known projects that do this are the Checker Framework and Project Lombok. Maybe you could take inspiration from their implementations, or even write your annotation processor on top of one of them.

    大概意思是,java annotation processer 只能拿到声明级别的信息,如类,方法的声明相关信息,拿不到其定义的内容。要想拿到类和方法定义的具体内容,需要使用到AST。

    鉴于我的需要只是拿到源文件的内容,我还是使用读取文件的方式好了。。。

    19 条回复    2020-06-02 15:08:12 +08:00
    freebird1994
        1
    freebird1994  
       2020-06-01 22:05:32 +08:00 via Android
    将类注入到 spring 容器中。实现 beanPostProcessor 。可以对注入容器的 bean 进行操作
    freebird1994
        2
    freebird1994  
       2020-06-01 22:09:16 +08:00 via Android
    @freebird1994 我好像理解错了楼主的意思?拿源代码?这个怕是只能通过类似 asm 等去获取字节码吧?还能拿到源代码么…看下楼下有没有大佬指点一下
    luckylo
        3
    luckylo  
       2020-06-01 22:12:05 +08:00 via Android
    个人觉得不可能。注解只在源代码中生效,编译后被擦除了。根本不能拿到任何东西
    fantastM
        4
    fantastM  
       2020-06-01 22:53:47 +08:00
    楼主说的 annotation processor 应该是 https://docs.oracle.com/javase/8/docs/api/javax/annotation/processing/AbstractProcessor.html

    这是作用在 javac 阶段的,类似于 Lombok 的注解
    Jrue0011
        5
    Jrue0011  
       2020-06-01 22:56:12 +08:00
    额。。反正是源码级别,获取到类名后根据是外部类、内部类在整个项目目录下找对应的源码文件读取?
    inwar
        6
    inwar  
       2020-06-01 22:59:21 +08:00 via Android
    想到个思路,打包的时候把源码复制一份到 resource, 注解改成 runtime,获取带包名的类名, 根据长类名读取 resouece 目录下源码文件。

    有点黑魔法,不知道楼下有没有好的方案
    Jrue0011
        7
    Jrue0011  
       2020-06-01 23:00:05 +08:00
    @Jrue0011 就是 4L 说的注解处理器
    Jirajine
        8
    Jirajine  
       2020-06-01 23:02:36 +08:00 via Android
    annotation 类似卫生宏吧,这种需求应该没问题才对。
    asanelder
        9
    asanelder  
    OP
       2020-06-01 23:04:56 +08:00
    @fantastM 是这个处理器
    @Jrue0011 看你的思路,是想在 abstractprocessor 中,想办法得到源文件的路径,然后通过读文件的文件来得到?
    @inwar 铁子,这个只是注解处理阶段,还没到打包呢,连 class 文件还没生成呢,只是处理源文件。

    我的意思是,有没有相关的 annotation api 可以得到 source code. 比如说 TypeElement 就已经表示源文件中的一个类型结构了,按道理来说,通过 TypeElement 就可以得到它所表示的结构信息,也就是相关的 souce code,但我找了半天,好像没有。
    asanelder
        10
    asanelder  
    OP
       2020-06-01 23:05:50 +08:00
    @Jirajine #8 请明示,没看懂。。。
    Jirajine
        11
    Jirajine  
       2020-06-01 23:40:47 +08:00 via Android
    @asanelder 又看了一下,我弄错了,annotation 只能存元数据,你可以把类当参数传给你的 annotation 。
    如果需要注入代码的话可以通过反射,参考这个 https://stackoverflow.com/questions/1079343/java-simple-technique-for-annotation-based-code-injection
    zengmingyang96
        12
    zengmingyang96  
       2020-06-02 00:06:51 +08:00
    用构建工具来做这件事情或许更好
    asanelder
        13
    asanelder  
    OP
       2020-06-02 00:17:04 +08:00
    @zengmingyang96 #12 嗯,应该是另一种思路,只是最近突然想起 annotation,正好有一个小需求,就练习一下下
    wangyanrui
        14
    wangyanrui  
       2020-06-02 08:43:43 +08:00
    抄一下 Lombok 应该可以的吧
    guyeu
        15
    guyeu  
       2020-06-02 10:18:04 +08:00
    原始需求是啥呢。。如果你发现一种实现很别扭,或许可以重新考虑下需求。
    gaius
        16
    gaius  
       2020-06-02 13:01:59 +08:00 via Android
    读源码不得读 java 文件吗,要么反编译 class 。。不知道你想干什么,如果是增强类可以用 cglib 之类的
    strawberryBug
        17
    strawberryBug  
       2020-06-02 13:40:48 +08:00
    注解都是要设定 @Target 的,仅能拿到 Target 支持的类型(枚举类)
    asanelder
        18
    asanelder  
    OP
       2020-06-02 14:22:53 +08:00
    @guyeu #15
    @gaius #16
    我的需求就是想根据被注解的 java 源文件生成 markdown 文件 ,而生成的 markdown 文件中,需要 java 源文件中的代码
    guyeu
        19
    guyeu  
       2020-06-02 15:08:12 +08:00
    @asanelder #18 openjdk 或者说 javac 没有内置这样的功能,据我所知,也没有一个使用广泛的工具可以实现这样的功能。或许可以通过代码的合理组织,结合 asciidoc 这样可以包含其他文本文件的标记语言,实现类似的效果。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   2551 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 24ms · UTC 01:22 · PVG 09:22 · LAX 17:22 · JFK 20:22
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.