java AbstractProcessor 编译时注解 (JSR 269)

写在前面

下一篇:java AbstractProcessor 编译时注解(API)

Lombok 的getter、setter如何实现的?

答案就在AbstractProcessor 身上,继承AbstractProcessor 抽象类,java文件在编译时编译器会检查AbstractProcessor的子类,并根据这些子类的内容,对java文件进行动态修改,再生成class文件。

1、实现编译时注解

注意:不要将AbstractProcessor 和 使用该AbstractProcessor 的类写在同一个项目中

1.1、实现步骤

以maven项目为例(将实现编译时注解的功能放到项目b ,测试使用这个功能在项目a)

项目结构:

在这里插入图片描述

1.1.1、项目b的内容

b的pom.xml

    <properties>
        <maven.compiler.source>1.8</maven.compiler.source>
        <maven.compiler.target>1.8</maven.compiler.target>
    </properties>

    <dependencies>

        <!-- 提供@AutoService注解,让AbstractProcessor子类被编译器发现 -->
        <!-- 如果不想使用@AutoService注解,也可以在resources/META-INF/services/javax.annotation.processing.Processor中添加AbstractProcessor的子类 -->
        <dependency>
            <groupId>com.google.auto.service</groupId>
            <artifactId>auto-service</artifactId>
            <version>1.0-rc5</version>
        </dependency>

        <!-- 提供JCTree等一些功能api -->
        <dependency>
            <groupId>com.sun</groupId>
            <artifactId>tools</artifactId>
            <version>1.8</version>
            <scope>system</scope>
            <systemPath>${java.home}/../lib/tools.jar</systemPath>
        </dependency>

    </dependencies>

b的HelloWorld.java

@Target({ElementType.METHOD})
@Retention(RetentionPolicy.SOURCE)
public @interface HelloWorld {
}

b的MyProcessor.java

import com.google.auto.service.AutoService;
import com.sun.tools.javac.model.JavacElements;
import com.sun.tools.javac.processing.JavacProcessingEnvironment;
import com.sun.tools.javac.tree.JCTree;
import com.sun.tools.javac.tree.TreeMaker;
import com.sun.tools.javac.util.Context;
import com.sun.tools.javac.util.List;

import javax.annotation.processing.*;
import javax.lang.model.SourceVersion;
import javax.lang.model.element.Element;
import javax.lang.model.element.TypeElement;
import java.util.Iterator;
import java.util.Set;

@SupportedAnnotationTypes("cc.HelloWorld")
@SupportedSourceVersion(SourceVersion.RELEASE_7)
@AutoService(Processor.class)
public class MyProcessor extends AbstractProcessor {
    @Override
    public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
        Context context = ((JavacProcessingEnvironment) this.processingEnv).getContext();
        JavacElements elementUtils = (JavacElements) this.processingEnv.getElementUtils();
        TreeMaker treeMaker = TreeMaker.instance(context);

        JCTree.JCMethodDecl jcMethodDecl;
        for (Iterator var7 = roundEnv.getElementsAnnotatedWith(HelloWorld.class).iterator(); var7.hasNext(); jcMethodDecl.body = treeMaker.Block(0L, List.of(treeMaker.Exec(treeMaker.Apply(List.nil(), treeMaker.Select(treeMaker.Select(treeMaker.Ident(elementUtils.getName("System")), elementUtils.getName("out")), elementUtils.getName("println")), List.of(treeMaker.Literal("这是HelloWorld打印的")))), jcMethodDecl.body))) {
            Element element = (Element) var7.next();
            jcMethodDecl = (JCTree.JCMethodDecl) elementUtils.getTree(element);
            treeMaker.pos = jcMethodDecl.pos;
        }
        return false;
    }
}
1.1.2、项目a的内容

a的pom.xml

    <properties>
        <maven.compiler.source>1.8</maven.compiler.source>
        <maven.compiler.target>1.8</maven.compiler.target>
    </properties>
    <dependencies>
        <!-- 引入有编译时注解 @HelloWorld 的包 -->
        <dependency>
            <groupId>org.example</groupId>
            <artifactId>b</artifactId>
            <version>1.0</version>
            <scope>compile</scope>
        </dependency>
    </dependencies>

a的Test.java

import cc.HelloWorld;

public class Test {
    @HelloWorld
    public static void main(String[] args) {
        System.out.println("这是Test自己打印的");
    }
}

启动Test试试

在这里插入图片描述
看一下编译后的文件Test.class

在这里插入图片描述
Test.class有两行System.out.println,一行是Test.java原本就有的,一行是@HelloWorld注解动态加入的

1.2、问题与报错

1、java: 服务配置文件不正确, 或构造处理程序对象javax.annotation.processing.Processor…
在这里插入图片描述
解决方法:这可能是由于动态注解的代码有改动,但未重新编译class文件造成的,删掉target重新编译即可

2、注解没效果
解决方法:你可能将AbstractProcessor的定义与使用放在了同一个项目中,不要将AbstractProcessor 和 使用该AbstractProcessor 的类写在同一个项目中,会因为AbstractProcessor 没有预编译导致报错或没效果

2、相关API

参考下一篇:java AbstractProcessor 编译时注解(API)

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值