每天学习一点点之注解处理器 APT

news2024/12/23 19:28:21

APT(Annotation Processing Tool)是一种处理注解的工具,它能够对源代码文件进行检测并找出其中的注解,然后对其进行额外的处理。由于注解处理过程是在编译时完成的,并不会影响程序的运行时性能

APT 能做什么?

APT 主要用于在编译时生成、修改或者处理代码。它可以用于创建新的源文件,但不能修改已经存在的源文件。一般有这么几种常用场景:

  1. 生成源代码:但是要注意这跟 Lombok 还是有一定区别的,Lombok 可以修改已经存在的类,这是 APT 无法做到的
  2. 编译时检查:APT 可以用于检查代码中的错误或者潜在问题。
  3. 生成文档:APT 可以用于从注解中提取信息,然后生成文档。

APT 工作流程

APT 的工作流程可以分为以下几个步骤:

  1. 收集源文件:APT 首先会收集所有的源文件。
  2. 解析源文件:然后,APT 会解析源文件,找出其中的注解。
  3. 调用注解处理器:对于每个找到的注解,APT 会调用相应的注解处理器。
  4. 生成源文件:注解处理器可以生成新的源文件。
  5. 编译源文件:最后,APT 会编译所有的源文件(包括原来的源文件和新生成的源文件)。

APT 在 Spring Boot Configuration Processor 中的使用

Spring Boot Configuration Processor是一个在编译时生成额外的元数据文件的工具,这些文件可以提供给IDE,以便在编辑 application.properties 或 application.yml 文件时提供自动完成和其他辅助功能。它也是基于 APT 在编译时扫描源代码,并生成这些元数据文件。

可以查看 ConfigurationMetadataAnnotationProcessor类,它是注解处理器,在编译时被调用:

//这个方法在每一轮注解处理中被调用。它首先找到所有的@ConfigurationProperties注解的类,然后对每一个类生成元数据	
@Override
	public boolean process(Set<? extends TypeElement> annotations,
			RoundEnvironment roundEnv) {
		this.metadataCollector.processing(roundEnv);
		Elements elementUtils = this.processingEnv.getElementUtils();
		TypeElement annotationType = elementUtils
				.getTypeElement(configurationPropertiesAnnotation());
		if (annotationType != null) { // Is @ConfigurationProperties available
			for (Element element : roundEnv.getElementsAnnotatedWith(annotationType)) {
				processElement(element);
			}
		}
		TypeElement endpointType = elementUtils.getTypeElement(endpointAnnotation());
		if (endpointType != null) { // Is @Endpoint available
			getElementsAnnotatedOrMetaAnnotatedWith(roundEnv, endpointType)
					.forEach(this::processEndpoint);
		}
		if (roundEnv.processingOver()) {
			try {
				writeMetaData();
			}
			catch (Exception ex) {
				throw new IllegalStateException("Failed to write metadata", ex);
			}
		}
		return false;
	}

APT 使用示例

这里基于 APT 实现一个注解,用于生成 Builder 模式代码的注解处理器。

首先需要定义一个注解:

/**
 * @author Dongguabai
 * @description
 * @date 2024-03-27 20:49
 */
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.SOURCE)
public @interface GenerateGettersSetters {
}

然后需要定义一个注解处理器。注解处理器需要继承 AbstractProcessor 类,并重写 process 方法。

/**
 * @author dongguabai
 * @date 2024-03-28 13:58
 */
@SupportedAnnotationTypes("io.github.dongguabai.apt.BuilderProperty")
@SupportedSourceVersion(SourceVersion.RELEASE_8)
public class BuilderProcessor extends AbstractProcessor {

    @Override
    public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
        for (Element element : roundEnv.getElementsAnnotatedWith(BuilderProperty.class)) {
            if (element.getKind() == ElementKind.METHOD) {
                ExecutableElement method = (ExecutableElement) element;
                String className = ((TypeElement) method.getEnclosingElement()).getSimpleName().toString();
                String fullClassName = ((TypeElement) method.getEnclosingElement()).getQualifiedName().toString();
                String packageName = ((PackageElement) method.getEnclosingElement().getEnclosingElement()).getQualifiedName().toString();
                String methodName = method.getSimpleName().toString();
                String parameterType = method.getParameters().get(0).asType().toString();

                try {
                    JavaFileObject file = processingEnv.getFiler().createSourceFile(packageName + "." + className + "Builder");
                    try (Writer writer = file.openWriter()) {
                        writer.write("package " + packageName + ";\n\n");
                        writer.write("public class " + className + "Builder {\n");
                        writer.write("    private " + fullClassName + " instance = new " + fullClassName + "();\n");
                        writer.write("    public " + className + "Builder " + methodName + "(" + parameterType + " value) {\n");
                        writer.write("        instance." + methodName + "(value);\n");
                        writer.write("        return this;\n");
                        writer.write("    }\n");
                        writer.write("    public " + fullClassName + " build() {\n");
                        writer.write("        return instance;\n");
                        writer.write("    }\n");
                        writer.write("}\n");
                    }
                } catch (IOException e) {
                    processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, e.getMessage());
                }
            }
        }
        return true;
    }
}

我这里将这个注解打成 JAR:

➜  apt-demo git:(master) ✗ mvn clean install
...
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 3.760 s
[INFO] Finished at: 2024-03-27T21:09:10+08:00
[INFO] Final Memory: 19M/192M
[INFO] ------------------------------------------------------------------------

User 类中使用这个注解:

/**
 * @author dongguabai
 * @date 2024-03-28 14:47
 */
public class User {

    private String username;

    public String getUsername() {
        return username;
    }

    @BuilderProperty
    public void setUsername(String username) {
        this.username = username;
    }
}

可以看到编译后自动生成了 UserBuilder

在这里插入图片描述

总结

APT 是一个可以在编译阶段发挥作用的强大工具,它能够识别并处理源代码中的注解。APT 的主要用途包括生成新的源代码、执行编译时检查以及生成文档等。APT 能够生成新的源代码文件,但它无法修改已经存在的源文件,此外如果我们的项目需要使用 APT 生成的代码,可能还需要通过反射来处理,这其实也不太方便。

欢迎关注公众号:
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1553577.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

3D人体姿态估计项目 | 从2D视频中通过检测人体关键点来估计3D人体姿态实现

项目应用场景 人体姿态估计是关于图像或视频中人体关节的 2D 或 3D 定位。一般来说&#xff0c;这个过程可以分为两个部分&#xff1a;(1) 2D 视频中的 2D 关键点检测&#xff1b;(2) 根据 2D 关键点进行 3D 位姿估计。这个项目使用 Detectron2 从任意的 2D 视频中检测 2D 关节…

车载以太网AVB交换机 gptp透明时钟 8口 千兆/百兆可切换 SW1100TR

SW1100TR车载以太网交换机 一、产品简要分析 8端口千兆和百兆混合车载以太网交换机&#xff0c;其中包含2个通道的1000BASE-T1采用罗森博格H-MTD接口&#xff0c;5通道100BASE-T1泰科MATEnet接口和1个通道1000BASE-T标准以太网(RJ45接口)&#xff0c;可以实现车载以太网多通道…

【LeetCode】LeetCode 547. 省份数量(Java版 什么是并查集)

&#x1f4dd;个人主页&#xff1a;哈__ 期待您的关注 一、题目描述 有 n 个城市&#xff0c;其中一些彼此相连&#xff0c;另一些没有相连。如果城市 a 与城市 b 直接相连&#xff0c;且城市 b 与城市 c 直接相连&#xff0c;那么城市 a 与城市 c 间接相连。 省份 是一组直…

STM32看似无法唤醒的一种异常现象分析

1. 引言 STM32 G0 系列产品具有丰富的外设和强大的处理性能以及良好的低功耗特性&#xff0c;被广泛用于各类工业产品中&#xff0c;包括一些需要低功耗需求的应用。 2. 问题描述 用户使用 STM32G0B1 作为汽车多媒体音响控制器的控制芯片&#xff0c;用来作为收音机频道存贮…

【有芯职说】数字芯片BES工程师

一、 数字芯片BES工程师简介 今天来聊聊数字芯片BES工程师&#xff0c;其中BES是Back End Support的缩写&#xff0c;就是后端支持的意思。其实这个岗位是数字IC前端设计和数字IC后端设计之间的一座桥&#xff0c;完成从寄存器传输级设计到具体工艺的mapping和实现。这个岗位在…

[flume$1]记录一个启动flume配置的错误

先总结&#xff1a;Flume配置文件后面&#xff0c;不能跟注释 报错代码&#xff1a; [ERROR - org.apache.flume.SinkRunner$PollingRunner.run(SinkRunner.java:158)] Unable to deliver event. Exception follows. org.apache.flume.EventDeliveryException: Failed to open…

如何在 Mac Pro 上恢复丢失的数据?

无论您多么努力&#xff0c;几乎不可能永远不会无意中删除 Mac 上的文件。当您得知删除后清空了垃圾箱时&#xff0c;您的处境可能看起来很黯淡。不要灰心。我们将教您如何使用本机操作系统功能或数据恢复工具恢复丢失的数据。奇客数据恢复Mac版可帮助恢复已从 Mac Pro 计算机上…

《Vision mamba》论文笔记

原文出处&#xff1a; [2401.09417] Vision Mamba: Efficient Visual Representation Learning with Bidirectional State Space Model (arxiv.org) 原文笔记&#xff1a; What&#xff1a; Vision Mamba: Efficient Visual Representation Learning with Bidirectional St…

YOLOv9 实现多目标跟踪

YOLOv9项目结合了YOLOv9的快速目标检测能力和DeepSORT的稳定跟踪能力&#xff0c;实现了对视频流中多个对象的实时、准确检测和跟踪。在具体应用中&#xff0c;该项目能够对视频中的行人、车辆或其他物体进行实时定位、识别和持续跟踪&#xff0c;即使在复杂环境、对象互相遮挡…

SlerfTools:简化操作,激发Solana生态创新潜能

在区块链世界的快速演变中,Solana生态系统以其独特的高性能吸引了全球的目光。然而,随着生态系统的蓬勃发展,用户和开发者面临的挑战也日渐增多。正是在这样的背景下,一个名为SlerfTools的新星项目应运而生,它承诺将为Solana带来一场革命性的变革。 项目的诞生 SlerfTools并非…

原创度检测工具分享,文章质量检测方便又简单

文章检测有利于我们了解文章内容的质量高低&#xff0c;而在以往我们检测文章只能依靠手动去检测&#xff0c;这是相当消耗工作时间的&#xff0c;但是在原创度检测工具出来之后&#xff0c;很多人开始检测文章质量就改用原创度检测工具了&#xff0c;因为使用原创度检测工具是…

YOLOv5-小知识记录(四)

0. 写在前面 本篇介绍SPP模块、FPN模块模块&#xff0c;主要也是对YOLOv5的内容的补充&#xff1a; Yolo系列算法-理论部分-YOLOv4-CSDN博客 Yolo系列算法-理论部分-YOLOv5-CSDN博客 上一篇&#xff1a; YOLOv5-小知识记录(三)-CSDN博客 1. PANet&#xff08;Path A…

49 el-input 的 模型 视图 双向同步

前言 这里来看一下 el-input 这边的 数据 和 视图的双向绑定 最开始 我以为 这部分的处理应该是 vue 这边实现的, 但是跟踪调试了一下 发现这部分的处理是业务这边 自己实现的 这部分 还是有一些 值得记录的东西, 从这里 要去理解的而是 vue 这边从宏观的框架上面来说 帮我们…

mac系统使用经验

mac安装brew brew是macos下的一个包管理工具&#xff0c;类似与centos的yum&#xff0c;ubuntu的apt-get等。 自动脚本(全部国内地址)&#xff08;在Mac os终端中复制粘贴回车下面这句话) /bin/zsh -c "$(curl -fsSL https://gitee.com/cunkai/HomebrewCN/raw/master/H…

基于CNN-RNN的动态手势识别系统实现与解析

一、环境配置 为了成功实现基于CNN-RNN的动态手势识别系统&#xff0c;你需要确保你的开发环境已经安装了以下必要的库和工具&#xff1a; Python&#xff1a;推荐使用Python 3.x版本&#xff0c;作为主要的编程语言。TensorFlow&#xff1a;深度学习框架&#xff0c;用于构建…

开放平台 - 互动玩法演进之路

本期作者 1. 背景 随着直播业务和用户规模日益壮大&#xff0c;如何丰富直播间内容、增强直播间内用户互动效果&#xff0c;提升营收数据变得更加关键。为此&#xff0c;直播互动玩法应运而生。通过弹幕、礼物、点赞、大航海等方式&#xff0c;用户可以参与主播的直播内容。B站…

书生·浦语大模型实战营(第二期):书生·浦语大模型全链路开源体系

非常开心能够参加到第二期的书生浦语大模型实战营&#xff0c;经过第一期的学习&#xff0c;初步了解了如何使用xtuner对模型进行微调&#xff0c;以及如何部署。遗憾的是没有更加深入学习并实现一个项目&#xff0c;此次学习过程中希望可以更进一步。 大模型称为发展通用人工…

安卓国内ip代理app,畅游网络

随着移动互联网的普及和快速发展&#xff0c;安卓手机已经成为我们日常生活和工作中不可或缺的一部分。然而&#xff0c;由于地理位置、网络限制或其他因素&#xff0c;我们有时需要改变或隐藏自己的IP地址。这时&#xff0c;安卓国内IP代理App便成为了一个重要的工具。虎观代理…

C++——C++11线程库

目录 一&#xff0c;线程库简介 二&#xff0c;线程库简单使用 2.1 传函数指针 ​编辑 2.2 传lamdba表达式 2.3 简单综合运用 2.4 线程函数参数 三&#xff0c;线程安全问题 3.1 为什么会有这个问题&#xff1f; 3.2 锁 3.2.1 互斥锁 3.2.2 递归锁 3.3 原子操作 3…

Java代码混淆技术的进阶应用与优化策略探讨

摘要 本文探讨了代码混淆在保护Java代码安全性和知识产权方面的重要意义。通过混淆技术&#xff0c;可以有效防止代码被反编译、逆向工程或恶意篡改&#xff0c;提高代码的安全性。常见的Java代码混淆工具如IPAGuard、Allatori、DashO、Zelix KlassMaster和yGuard等&#xff0…