当前位置: 首页 > 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 信息用于流上的实时处理,这种场景我们…...

VLC技术重构:模块化架构深度解析与跨平台媒体处理突破

VLC技术重构&#xff1a;模块化架构深度解析与跨平台媒体处理突破 【免费下载链接】vlc VLC media player - All pull requests are ignored, please use MRs on https://code.videolan.org/videolan/vlc 项目地址: https://gitcode.com/gh_mirrors/vl/vlc 技术洞察&…...

不止于透传:用VirtIO-GPU为你的KVM虚拟机开启3D加速(附XML配置详解)

VirtIO-GPU虚拟化加速实战&#xff1a;从原理到配置的深度解析 在虚拟化技术日益成熟的今天&#xff0c;GPU加速已成为开发测试、图形工作站和云桌面等场景的刚需。传统GPU透传方案虽然性能接近原生&#xff0c;但受限于硬件数量且缺乏灵活性。VirtIO-GPU结合virglrenderer的软…...

虚假信息注入下异构系统弹性纳什均衡【附代码】

✨ 长期致力于博弈论、分布式纳什均衡、虚假信息注入攻击、线性系统、参数不确定、事件触发研究工作&#xff0c;擅长数据搜集与处理、建模仿真、程序编写、仿真设计。 ✅ 专业定制毕设、代码 ✅ 如需沟通交流&#xff0c;点击《获取方式》 &#xff08;1&#xff09;虚假信息观…...

Task Slack集成:团队协作的任务管理终极指南

Task Slack集成&#xff1a;团队协作的任务管理终极指南 【免费下载链接】task A fast, cross-platform build tool inspired by Make, designed for modern workflows. 项目地址: https://gitcode.com/gh_mirrors/ta/task Task 是一款受 Make 启发的快速跨平台构建工具…...

如何用拯救者工具箱完全掌控联想笔记本:开源硬件管理终极指南

如何用拯救者工具箱完全掌控联想笔记本&#xff1a;开源硬件管理终极指南 【免费下载链接】LenovoLegionToolkit Lightweight Lenovo Vantage and Hotkeys replacement for Lenovo Legion laptops. 项目地址: https://gitcode.com/gh_mirrors/le/LenovoLegionToolkit 你…...

为Claude Code配置Taotoken解决账号被封与Token不足的烦恼

&#x1f680; 告别海外账号与网络限制&#xff01;稳定直连全球优质大模型&#xff0c;限时半价接入中。 &#x1f449; 点击领取海量免费额度 为Claude Code配置Taotoken解决账号被封与Token不足的烦恼 对于依赖Claude Code进行编程辅助的开发者来说&#xff0c;直接使用官方…...

终端里的编程副驾:DeepSeek-TUI-项目深度拆解,实测与原理分析

刷 GitHub Trending 又看到一个挺有意思的东西&#xff1a;DeepSeek-TUI。说白了&#xff0c;就是把 DeepSeek V4 这个编程大模型&#xff0c;直接塞进了你的终端里。 这玩意儿不是简单的 CLI 包装。我跑了一下 curl 看 README&#xff0c;发现他们搞了个完整的 TUI&#xff08…...

Next-Enterprise:基于Next.js的企业级应用启动模板全解析

1. 项目概述&#xff1a;为什么说 Next-Enterprise 是“企业级”的&#xff1f;如果你正在用 Next.js 开发一个中后台管理系统、一个 SaaS 应用&#xff0c;或者任何需要“开箱即用”的现代企业级功能的应用&#xff0c;那么你大概率经历过这样的场景&#xff1a;项目初始化后&…...

LLM与图数据库融合:自然语言驱动知识图谱查询实战

1. 项目概述&#xff1a;当LLM遇见图数据库&#xff0c;知识推理的新范式最近在探索如何让大语言模型&#xff08;LLM&#xff09;更好地处理复杂、结构化的知识时&#xff0c;我遇到了一个非常有意思的项目&#xff1a;dylanhogg/llmgraph。这个项目本质上是一个桥梁&#xff…...

ARM CoreSight TRBPIDR寄存器详解与调试技巧

1. ARM CoreSight TRBPIDR寄存器概述在嵌入式系统调试领域&#xff0c;ARM CoreSight架构提供了一套完整的调试和追踪解决方案。其中TRBPIDR&#xff08;Trace Buffer Peripheral Identification Register&#xff09;系列寄存器是识别和配置追踪缓冲区的关键组件。这些寄存器遵…...