当前位置: 首页 > news >正文

Java编译期注解处理器AbstractProcessor使用

我们接触的注解主要分为以下两类

  1. 运行时注解:通过反射在运行时动态处理注解的逻辑
  2. 编译时注解:通过注解处理器在编译期动态处理相关逻辑

编译期注解我们常用的有Lombok,在class文件中自动生成get和set方法

解编译期处理流程最关键的一个类就是javax.annotation.processing.Processor注解处理器的接口类,遵循SPI规约进行拓展,我们所有需要对编译期处理注解的逻辑都需要实现这个Processor接口,当然,AbstractProcessor 抽象类帮我们写好了大部分都流程,所以我们只需要实现这个抽象类就可以很方便的定义一个注解处理器

自定义注解处理器

(1)tools.jar加入到idea的类路径

注意:在idea自定义编译处理器前,需要把tools.jar加入到idea的类路径中(文件--》项目结构--》平台设置--》SDK-->类路径--》把tools.jar加入进去),如下图:

(2)建maven父子项目

1)父项目demo的pom.xml配置如下
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.7.3</version><relativePath/> <!-- lookup parent from repository --></parent><groupId>com.wbq</groupId><artifactId>demo</artifactId><version>0.0.1</version><packaging>pom</packaging><name>demo</name><description>demo project for Spring Boot</description><properties><java.version>1.8</java.version></properties><modules><module>child1</module><module>child2</module><module>child3</module></modules><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter</artifactId><exclusions><!-- 去掉默认配置 --><exclusion><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-logging</artifactId></exclusion></exclusions></dependency><!--  log4j2依赖 --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-log4j2</artifactId><version>2.7.3</version></dependency><!-- hutool --><dependency><groupId>cn.hutool</groupId><artifactId>hutool-all</artifactId><version>5.8.6</version></dependency></dependencies><build><plugins><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-compiler-plugin</artifactId><configuration><source>1.8</source><target>1.8</target><encoding>UTF-8</encoding></configuration></plugin></plugins></build></project>
2)子项目child3的pom.xml如下
  • pom.xml
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns="http://maven.apache.org/POM/4.0.0"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><parent><artifactId>demo</artifactId><groupId>com.wbq</groupId><version>0.0.1</version></parent><modelVersion>4.0.0</modelVersion><artifactId>child3</artifactId><dependencies><!-- https://mvnrepository.com/artifact/javax.annotation/javax.annotation-api --><dependency><groupId>javax.annotation</groupId><artifactId>javax.annotation-api</artifactId><version>1.3.2</version></dependency></dependencies><build><!-- 指定JDK编译版本 --><plugins><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-compiler-plugin</artifactId><configuration><source>1.8</source><target>1.8</target><encoding>UTF-8</encoding><compilerArgs><arg>-proc:none</arg></compilerArgs><compilerArguments><bootclasspath>${java.home}/lib/rt.jar;${java.home}/lib/jce.jar;${java.home}/../lib/tools.jar</bootclasspath></compilerArguments></configuration></plugin></plugins></build></project>
  • 注解类
package com.wbq.child3.processor;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.RUNTIME)
public @interface MyFieldAnnotation {}
  • AbstractProcessor实现类
    在有MyFieldAnnotation注解的类的方法中添加代码:System.out.println("hello world");
package com.wbq.child3.processor;import com.sun.tools.javac.api.JavacTrees;
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.tree.TreeTranslator;
import com.sun.tools.javac.util.Context;
import com.sun.tools.javac.util.List;
import com.sun.tools.javac.util.Names;import javax.annotation.processing.*;
import javax.lang.model.SourceVersion;
import javax.lang.model.element.TypeElement;
import javax.tools.Diagnostic;
import java.util.Set;/*** 在有MyFieldAnnotation注解的类的方法中添加代码:System.out.println("hello world");*/
@SupportedAnnotationTypes("com.wbq.child3.processor.MyFieldAnnotation")
@SupportedSourceVersion(SourceVersion.RELEASE_8)
//@AutoService(Processor.class)
public class MyFieldProcessor extends AbstractProcessor {/*** 抽象语法树*/private JavacTrees javacTrees;/*** AST*/private TreeMaker treeMaker;/*** 标识符*/private Names names;/*** 日志处理*/private Messager messager;private Filer filer;public synchronized void init(ProcessingEnvironment processingEnv) {System.out.println("初始化");processingEnv.getMessager().printMessage(Diagnostic.Kind.WARNING, "初始化 ");javacTrees = JavacTrees.instance(processingEnv);Context context = ((JavacProcessingEnvironment)processingEnv).getContext();this.treeMaker = TreeMaker.instance(context);super.init(processingEnv);this.names = Names.instance(context);}@Overridepublic boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {System.out.println("注解处理器");annotations.stream().flatMap(t -> roundEnv.getElementsAnnotatedWith(t).stream()).forEach(t -> {JCTree tree = javacTrees.getTree(t);tree.accept(new TreeTranslator() {@Overridepublic void visitMethodDef(JCTree.JCMethodDecl tree) {System.out.println("hello world");JCTree.JCStatement sysout = treeMaker.Exec(treeMaker.Apply(List.nil(),select("System.out.println"),List.of(treeMaker.Literal("hello world"))));//覆盖原有的语句块tree.body.stats = tree.body.stats.append(sysout);super.visitMethodDef(tree);}});});return true;}private JCTree.JCFieldAccess select(JCTree.JCExpression selected,String expressive){return treeMaker.Select(selected, names.fromString(expressive));}private JCTree.JCFieldAccess select(String expressive){String[] exps=expressive.split("\\.");JCTree.JCFieldAccess access=treeMaker.Select(ident(exps[0]),names.fromString(exps[1]));int index=2;while(index<exps.length){access=treeMaker.Select(access, names.fromString(exps[index++]));}return access;}private JCTree.JCIdent ident(String name){return treeMaker.Ident(names.fromString(name));}}
  • 指定插入式注解类

在resources下新建META-INF文件夹,META-INF文件夹下新建services文件夹,services文件夹下新建文件(文件名=javax.annotation.processing.Processor)

src/main/resources/META-INF/services/javax.annotation.processing.Processor

javax.annotation.processing.Processor文件中写入

com.wbq.child3.processor.MyFieldProcessor

3)新建子项目child2

child2使用child3中的注解

结构如下:

  • pom.xml文件如下:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><parent><artifactId>demo</artifactId><groupId>com.wbq</groupId><version>0.0.1</version></parent><modelVersion>4.0.0</modelVersion><artifactId>child2</artifactId><properties><maven.compiler.source>8</maven.compiler.source><maven.compiler.target>8</maven.compiler.target></properties><dependencies><dependency><groupId>com.wbq</groupId><artifactId>child3</artifactId><version>0.0.1</version></dependency></dependencies><build><plugins><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-compiler-plugin</artifactId><configuration><source>1.8</source><target>1.8</target><encoding>UTF-8</encoding></configuration></plugin></plugins></build></project>
  • 测试类如下:
package com.wbq.child2;import com.wbq.child3.processor.MyFieldAnnotation;
//child3中的注解
@MyFieldAnnotation
public class TestChild3Main {public static void main(String[] args) {System.out.println("main");}
}

(3)测试运行

  • 在maven中先编译child3,依次:clean、compile、package、install

在maven中编译child2,依次:clean、compile

在child2\target\classes\com\wbq\child2中生成了TestChild3Main.class文件,使用idea打开这个class文件,Main方法中添加了一行代码System.out.println("hello world");

相关文章:

Java编译期注解处理器AbstractProcessor使用

我们接触的注解主要分为以下两类 运行时注解&#xff1a;通过反射在运行时动态处理注解的逻辑编译时注解&#xff1a;通过注解处理器在编译期动态处理相关逻辑 编译期注解我们常用的有Lombok&#xff0c;在class文件中自动生成get和set方法 解编译期处理流程最关键的一个类就…...

JetBrains相关的IDE有哪些?

JetBrains是一家成立于2002年的捷克软件开发公司&#xff0c;总部位于捷克的布拉格&#xff0c;同时在俄罗斯的圣彼得堡及美国麻州波士顿等地设有办公室。该公司以其高质量的集成开发环境&#xff08;IDE&#xff09;产品而闻名&#xff0c;这些产品被广泛应用于各种编程语言和…...

Git-常规用法-含解决分支版本冲突解决方法

目录 前置条件 已经创建了Gitee账号 创建一个远程仓库 Git的优点 版本控制 Git 下载 Git的使用 检查Git的是否安装成功 git的常用命令 常用流程 Git 分支 分支流程 Git 远程仓库 远程仓库流程 特殊 可能遇到的问题 前置条件 已经创建了Gitee账号 创建一个远程仓…...

基于springboot实现大型商场应急预案管理系统项目【项目源码+论文说明】

基于SpringBoot实现大型商场应急预案管理系统演示 摘要 随着信息技术在管理上越来越深入而广泛的应用&#xff0c;管理信息系统的实施在技术上已逐步成熟。本文介绍了大型商场应急预案管理系统的开发全过程。通过分析大型商场应急预案管理系统管理的不足&#xff0c;创建了一个…...

系统学c#:1、基础准备(软件下载与安装)

一、Vs软件下载与安装 访问Visual Studio官方网站&#xff1a; https://visualstudio.microsoft.com/zh-hans/downloads 下载Visual Studio 运行exe文件&#xff0c;点击“继续” 初始文件安装完成后选择我们需要安装的项&#xff0c;并勾选好必要的单个组件&#xff0c;设…...

解决CSS中鼠标移入到某个元素其子元素被遮挡的问题

我们在开发中经常遇到一种场景&#xff0c;就是给元素加提示信息&#xff0c;就是鼠标移入到盒子上面时&#xff0c;会出现提示信息这一功能&#xff0c;如果我们给盒子加了hover&#xff0c;当鼠标移入到盒子上时&#xff0c;让他往上移动5px&#xff0c;即transform: transla…...

【华为OD机试】虚拟理财游戏【C卷|100分】

【华为OD机试】-真题 !!点这里!! 【华为OD机试】真题考点分类 !!点这里 !! 题目描述 在一款虚拟游戏中生活,你必须进行投资以增强在虚拟游戏中的资产以免被淘汰出局。 现有一家Bank,它提供有若干理财产品 m 个,风险及投资回报不同,你有 N(元)进行投资,能接收的总风险…...

ssh 使用

ssh 使用 一、ssh 安装二、ssh 使用1. ssh 登录2. ssh-keygen 免密登录(1) ssh 生成密钥(2) 开启远程主机的密钥登陆(3) ssh 分发公钥 3. ssh-copy-id 复制公钥到远程主机4. scp 复制 系统环境: linux(ubuntu,debian,kali) 一、ssh 安装 sudo apt update sudo apt install op…...

Springboot+Vue项目-基于Java+MySQL的母婴商城系统(附源码+演示视频+LW)

大家好&#xff01;我是程序猿老A&#xff0c;感谢您阅读本文&#xff0c;欢迎一键三连哦。 &#x1f49e;当前专栏&#xff1a;Java毕业设计 精彩专栏推荐&#x1f447;&#x1f3fb;&#x1f447;&#x1f3fb;&#x1f447;&#x1f3fb; &#x1f380; Python毕业设计 &…...

Android多线程:Handler runOnUiThread 异步消息处理机制

目录 一&#xff0c;Android中的多线程问题 1.模拟耗时工作 2.Android开启子线程 二&#xff0c;在子线程中更新UI 1.异步消息处理机制 Handler 2.使用runOnUiThread更新UI 一&#xff0c;Android中的多线程问题 Android用户界面是与用户交互的接口&#xff0c;对于用户的…...

AndroidStudio 导出aar包,并使用

打包 1、确认当前选项是否勾选&#xff0c;如未勾选请先勾选。 2、勾选完成后重启Android Studio。 3、重启完成后&#xff0c;选中要打包的module 4、打包完成 使用 1.在项目中新建libs,放入aar文件。 2.修改配置 添加如下代码 flatDir {dirs("libs")}3.修改app…...

python与设计模式之工厂模式的那些事儿

一、工厂模式 工厂模式实现了按需创建的最佳模式&#xff0c;其目的是为了隐藏创建类的细节与过程&#xff0c;通过一个统一的接口来创建所需的对象。 话说没了皇位争夺权的皇三接到了一个外征的工作&#xff0c;始皇给了5个亿的经费让皇三组建一个军队。打权总是要进行武器采…...

什么是区块链?

简介 作者在学习虚拟机时突然发现有人提出如何在区块链开发一款轻量型jvm&#xff0c;由于对区块链不太了解&#xff0c;也不理解区块链为什么需要轻量型jvm。恰好最近有空&#xff0c;泡在图书馆找了本书《区块链导论》对相关知识进行了学习。 区块链系统&#xff1b; 特点…...

2022年电赛F题23年电赛D题-信号调制度测量装置说明中提到带通采样定律。

2022年电赛F题-信号调制度测量装置说明中提到带通采样定律。 23年电赛D题十分相似&#xff0c;但是22年载波达到了10M&#xff0c;根据奈奎斯特采样定理&#xff0c;我们知道想要分析出频谱不混叠的频谱图&#xff0c;采样率必须大于最大谐波的二倍。那么就意味着AD采样率要大…...

Rust面试宝典第2题:逆序输出整数

题目 写一个方法&#xff0c;将一个整数逆序打印输出到控制台。注意&#xff1a;当输入的数字含有结尾的0时&#xff0c;输出不应带有前导的0。比如&#xff1a;123的逆序输出为321&#xff0c;8600的逆序输出为68&#xff0c;-609的逆序输出为-906。 解析 这道题本身并没有什么…...

Linux笔记之查看docker容器目录映射

Linux笔记之查看docker容器目录映射 —— 2024-04-15 code review! docker inspect 容器ID或容器名 | grep -A 20 Mounts实践 grep -A 参数详解&#xff1a; grep 的 -A 参数用于在输出中包括匹配行后的指定数目的行。 使用 -A 参数 该参数的基本语法如下&#xff1a; …...

​​​​网络编程探索系列之——广播原理剖析

hello &#xff01;大家好呀&#xff01; 欢迎大家来到我的网络编程系列之广播原理剖析&#xff0c;在这篇文章中&#xff0c; 你将会学习到如何在网络编程中利用广播来与局域网内加入某个特定广播组的主机&#xff01; 希望这篇文章能对你有所帮助&#xff0c;大家要是觉得我写…...

jar包解压和重新打包

1、Windows系统上解压和重新打包jar包的命令&#xff1a; (1). 解压jar包&#xff1a; jar -xf yourJarFile.jar (2). 重新打包jar包&#xff1a; jar -cf newJarFile.jar * 2、Linux系统上解压和重新打包jar包的命令&#xff1a; (1). 解压jar包&#xff1a; unzip your…...

Python基于Django的微博热搜、微博舆论可视化系统

博主介绍&#xff1a;✌IT徐师兄、7年大厂程序员经历。全网粉丝15W、csdn博客专家、掘金/华为云//InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精彩专栏推荐订阅&#x1f447;&#x1f3…...

Flink SQL:debezium-json 格式的表一定是数据库的 CDC 数据吗?

debezium-json 格式有一种非常典型的应用场景,就是:上游(Source)是一张使用 Flink CDC 接入的关系数据库中的表,下游(Sink)是一张创建在 Kafka 上的表,这张表的 format 往往会定义为 debezium-json,以便 Flink 能获得全面的 CDC 信息用于流上的实时处理,这种场景我们…...

C++实现分布式网络通信框架RPC(3)--rpc调用端

目录 一、前言 二、UserServiceRpc_Stub 三、 CallMethod方法的重写 头文件 实现 四、rpc调用端的调用 实现 五、 google::protobuf::RpcController *controller 头文件 实现 六、总结 一、前言 在前边的文章中&#xff0c;我们已经大致实现了rpc服务端的各项功能代…...

黑马Mybatis

Mybatis 表现层&#xff1a;页面展示 业务层&#xff1a;逻辑处理 持久层&#xff1a;持久数据化保存 在这里插入图片描述 Mybatis快速入门 ![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/6501c2109c4442118ceb6014725e48e4.png //logback.xml <?xml ver…...

《Qt C++ 与 OpenCV:解锁视频播放程序设计的奥秘》

引言:探索视频播放程序设计之旅 在当今数字化时代,多媒体应用已渗透到我们生活的方方面面,从日常的视频娱乐到专业的视频监控、视频会议系统,视频播放程序作为多媒体应用的核心组成部分,扮演着至关重要的角色。无论是在个人电脑、移动设备还是智能电视等平台上,用户都期望…...

遍历 Map 类型集合的方法汇总

1 方法一 先用方法 keySet() 获取集合中的所有键。再通过 gey(key) 方法用对应键获取值 import java.util.HashMap; import java.util.Set;public class Test {public static void main(String[] args) {HashMap hashMap new HashMap();hashMap.put("语文",99);has…...

【快手拥抱开源】通过快手团队开源的 KwaiCoder-AutoThink-preview 解锁大语言模型的潜力

引言&#xff1a; 在人工智能快速发展的浪潮中&#xff0c;快手Kwaipilot团队推出的 KwaiCoder-AutoThink-preview 具有里程碑意义——这是首个公开的AutoThink大语言模型&#xff08;LLM&#xff09;。该模型代表着该领域的重大突破&#xff0c;通过独特方式融合思考与非思考…...

Map相关知识

数据结构 二叉树 二叉树&#xff0c;顾名思义&#xff0c;每个节点最多有两个“叉”&#xff0c;也就是两个子节点&#xff0c;分别是左子 节点和右子节点。不过&#xff0c;二叉树并不要求每个节点都有两个子节点&#xff0c;有的节点只 有左子节点&#xff0c;有的节点只有…...

Linux C语言网络编程详细入门教程:如何一步步实现TCP服务端与客户端通信

文章目录 Linux C语言网络编程详细入门教程&#xff1a;如何一步步实现TCP服务端与客户端通信前言一、网络通信基础概念二、服务端与客户端的完整流程图解三、每一步的详细讲解和代码示例1. 创建Socket&#xff08;服务端和客户端都要&#xff09;2. 绑定本地地址和端口&#x…...

2025季度云服务器排行榜

在全球云服务器市场&#xff0c;各厂商的排名和地位并非一成不变&#xff0c;而是由其独特的优势、战略布局和市场适应性共同决定的。以下是根据2025年市场趋势&#xff0c;对主要云服务器厂商在排行榜中占据重要位置的原因和优势进行深度分析&#xff1a; 一、全球“三巨头”…...

【Go语言基础【13】】函数、闭包、方法

文章目录 零、概述一、函数基础1、函数基础概念2、参数传递机制3、返回值特性3.1. 多返回值3.2. 命名返回值3.3. 错误处理 二、函数类型与高阶函数1. 函数类型定义2. 高阶函数&#xff08;函数作为参数、返回值&#xff09; 三、匿名函数与闭包1. 匿名函数&#xff08;Lambda函…...

libfmt: 现代C++的格式化工具库介绍与酷炫功能

libfmt: 现代C的格式化工具库介绍与酷炫功能 libfmt 是一个开源的C格式化库&#xff0c;提供了高效、安全的文本格式化功能&#xff0c;是C20中引入的std::format的基础实现。它比传统的printf和iostream更安全、更灵活、性能更好。 基本介绍 主要特点 类型安全&#xff1a…...