java高级特性 - APT

转载于:https://blog.csdn.net/kxkkl/article/details/119152813

准备

开始之前,需要引入jar包,一个是谷歌的工具包,帮助我们自动生成META-INF目录下的配置,另一个是生成class文件的工具

<dependency>
    <groupId>com.google.auto.service</groupId>
    <artifactId>auto-service</artifactId>
    <version>1.0-rc2</version>
</dependency>
<dependency>
    <groupId>com.squareup</groupId>
    <artifactId>javapoet</artifactId>
    <version>1.13.0</version>
</dependency>

开始

首先创建一个自定义注解,用于注解处理器识别,代码如下:

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;


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

然后创建注解处理器类,代码如下:

import com.google.auto.service.AutoService;
import com.squareup.javapoet.FieldSpec;
import com.squareup.javapoet.JavaFile;
import com.squareup.javapoet.TypeSpec;
import lombok.Getter;
import lombok.Setter;
import lombok.SneakyThrows;

import javax.annotation.processing.*;
import javax.lang.model.SourceVersion;
import javax.lang.model.element.Element;
import javax.lang.model.element.Modifier;
import javax.lang.model.element.TypeElement;
import javax.lang.model.util.Elements;
import javax.lang.model.util.Types;
import javax.tools.Diagnostic;
import java.util.Set;

@AutoService(Processor.class)
@SupportedAnnotationTypes("com.lushwe.Hello")
@SupportedSourceVersion(value = SourceVersion.RELEASE_8)
public class HelloAnnotationProcessor extends AbstractProcessor {

    private Elements elementUtils;
    private Types typeUtils;
    private Filer filer;
    private Messager messager;

    @Override
    public synchronized void init(ProcessingEnvironment processingEnvironment) {

        super.init(processingEnvironment);

        elementUtils = processingEnvironment.getElementUtils();
        typeUtils = processingEnvironment.getTypeUtils();
        messager = processingEnvironment.getMessager();
        filer = processingEnvironment.getFiler();

    }

    @Override
    @SneakyThrows
    public boolean process(Set<? extends TypeElement> set, RoundEnvironment roundEnvironment) {

        if (set.isEmpty()) {
            return false;
        }

        Set<? extends Element> elements = roundEnvironment.getElementsAnnotatedWith(Hello.class);
        for (Element element : elements) {
            parseElement(element);
        }
        return true;

    }

    private void parseElement(Element element) throws Exception {

        String packageName = elementUtils.getPackageOf(element).getQualifiedName().toString();
        String className = element.getSimpleName().toString();

        messager.printMessage(Diagnostic.Kind.NOTE, "=HelloProcessor=" + packageName + "/" + className);

        FieldSpec id = FieldSpec.builder(Long.class, "id")
                .addModifiers(Modifier.PRIVATE)
                .addJavadoc("ID")
                .build();
        FieldSpec name = FieldSpec.builder(String.class, "name")
                .addModifiers(Modifier.PRIVATE)
                .addJavadoc("名称")
                .build();

        TypeSpec typeSpec = TypeSpec.classBuilder("HelloWorld")
                .addModifiers(Modifier.PUBLIC)
                .addAnnotation(Getter.class)
                .addAnnotation(Setter.class)
                .addField(id)
                .addField(name)
                .build();

        JavaFile javaFile = JavaFile.builder(packageName, typeSpec)
                .build();

        // 写入
        javaFile.writeTo(filer);

    }
}

基本已经完成了,打成一个jar(一般都是通过jar引入)

使用

新建一个工程引入上面的jar,查看引入的jar在 META-INF.services 下面有一个 javax.annotation.processing.Processor 配置文件,里面是 com.lushwe.HelloAnnotationProcessor ,这个就是上面引入谷歌jar包 auto-service 自动生成的,不然的需要我们手工创建,虽然都可以,但是麻烦,这样比较方便,详细如图
image

创建一个配置类,代码注解 @Hello ,否则无法触发注解处理器

@Hello
public class HelloConfig {
}

然后编译即可触发注解处理器,然后就会在target目标自动生成代码
其中 classes 目录下,HelloConfig相同包下会生成 HelloWorld.class 代码如下,其中get set方法是 @Getter @Setter 帮我们创建的

package com.lushwe;

public class HelloWorld {
    private Long id;
    private String name;

    public HelloWorld() {
    }

    public Long getId() {
        return this.id;
    }

    public String getName() {
        return this.name;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public void setName(String name) {
        this.name = name;
    }
}

其中 generated-sources 目录下,会生成对应的HelloWorld.java代码,方便我们系统里面引入(没有这个代码的话,系统里面引用虽然能运行,但是在idea类似的开发工具里面显示报错,体验不好,注意这里仅仅是方便我们使用,不会像我们自己新增一个类一样要提交),如下:

package com.lushwe;

import java.lang.Long;
import java.lang.String;
import lombok.Getter;
import lombok.Setter;

@Getter
@Setter
public class HelloWorld {
  /**
   * ID
   */
  private Long id;

  /**
   * 名称
   */
  private String name;
}

截图证明
image

补充

本文仅演示了maven,有些使用gradle的小伙伴可能会遇到class文件能正常生成,但是java文件没生成,导致系统使用该类的地方报错,但是不影响编译、也能正常运行,不过体验不好,使用gradle的小伙伴,检查下面的配置是否有,没有添加下即可

buildscript {
  repositories {
    maven {
      url "https://plugins.gradle.org/m2/"
    }
  }
  dependencies {
    // 关键点1
    classpath "net.ltgt.gradle:gradle-apt-plugin:0.21"
  }
}

// 关键点1
apply plugin: "net.ltgt.apt-idea"

上面配置来自gradle 插件官网

posted @ 2023-08-02 17:52  蓝迷梦  阅读(103)  评论(0)    收藏  举报