Java编译时注解自动生成代码

# Java实战系列 - 使用APT编译期自动生成代码 本文主要介绍如何使用APT在编译期生成class文件 准备 开始之前,需要引入jar包,一个是谷歌的工具包,帮助我们自动生成META-INF目录下的配置,另一个是生成class文件的工具 <dependency> <groupId>com.google.auto.service</groupId> <artifactId>auto-service</artifactId> <version>1.0-rc2. 阅读详情

在开始之前,我们首先申明一个非常重要的问题:我们并不讨论那些在运行时(Runtime)通过反射机制运行处理的注解,而是讨论在编译时(Compile time)处理的注解。注解处理器是一个在javac中的,用来编译时扫描和处理的注解的工具。可以为特定的注解,注册自己的注解处理器。

一个注解的注解处理器,以Java代码(或者编译过的字节码)作为输入,生成文件(通常是.java文件)作为输出。可以生成Java代码,这些生成的Java代码是在生成的.java文件中,所以不能修改已经存在的Java类,例如向已有的类中添加方法。这些生成的Java文件,会同其他普通的手动编写的Java源代码一样被javac编译。

虚处理器AbstractProcessor

我们首先看一下处理器的API。每一个处理器都是继承于AbstractProcessor,如下所示:

public class MyProcessor extends AbstractProcessor {

    @Override
    public synchronized void init(ProcessingEnvironment env){ }

    @Override
    public boolean process(Set<? extends TypeElement> annoations, RoundEnvironment env) { }

    @Override
    public Set<String> getSupportedAnnotationTypes() { }

    @Override
    public SourceVersion getSupportedSourceVersion() { }

}
  • init(ProcessingEnvironment env): 每一个注解处理器类都必须有一个空的构造函数。然而,这里有一个特殊的init()方法,它会被注解处理工具调用,并输入ProcessingEnviroment参数。ProcessingEnviroment提供很多有用的工具类Elements,Types和Filer。
  • process(Set<? extends TypeElement> annotations, RoundEnvironment env): 这相当于每个处理器的主函数main()。 在这里写扫描、评估和处理注解的代码,以及生成Java文件。输入参数RoundEnviroment,可以让查询出包含特定注解的被注解元素。
  • getSupportedAnnotationTypes(): 这里必须指定,这个注解处理器是注册给哪个注解的。注意,它的返回值是一个字符串的集合,包含本处理器想要处理的注解类型的合法全称。换句话说,在这里定义你的注解处理器注册到哪些注解上。
  • getSupportedSourceVersion(): 用来指定你使用的Java版本。通常这里返回SourceVersion.latestSupported()。然而,如果有足够的理由只支持Java 6的话,也可以返回SourceVersion.RELEASE_6。推荐使用前者。

举一个简单例子

自动生成一个bean的结构文件

把
public class Student {
	public String stu_name;
	public String stu_id;
	public int stu_age;
}
转换为
{class:"com.robert.processor.Student",  
 fields:  
 {  
  stu_name:"java.lang.String",  
  stu_id:"java.lang.String",
  stu_age:"java.lang.Integer"
 }  
} 
首先声明注解

package com.robert.processor;

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

@Target({ ElementType.FIELD, ElementType.TYPE })
@Retention(RetentionPolicy.CLASS)
public @interface Serialize {

}
将注解加到Student类上
@Serialize
public class Student 

定义自己的解析器

package com.robert.processor;

import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.annotation.processing.AbstractProcessor;
import javax.annotation.processing.ProcessingEnvironment;
import javax.annotation.processing.RoundEnvironment;
import javax.lang.model.element.Element;
import javax.lang.model.element.ElementKind;
import javax.lang.model.element.TypeElement;
import javax.lang.model.element.VariableElement;
import javax.lang.model.util.ElementFilter;
import javax.lang.model.util.Elements;

public class MyProcessor extends AbstractProcessor {

	// 元素操作的辅助类
	Elements elementUtils;

	@Override
	public synchronized void init(ProcessingEnvironment processingEnv) {
		super.init(processingEnv);
		elementUtils = processingEnv.getElementUtils();
	}

	@Override
	public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
		// 获得被该注解声明的元素
		Set<? extends Element> elememts = roundEnv.getElementsAnnotatedWith(Serialize.class);
		TypeElement classElement = null;// 声明类元素
		List<VariableElement> fields = null;// 声明一个存放成员变量的列表
		// 存放二者
		Map<String, List<VariableElement>> maps = new HashMap<String, List<VariableElement>>();
		// 遍历
		for (Element ele : elememts) {
			// 判断该元素是否为类
			if (ele.getKind() == ElementKind.CLASS) {
				classElement = (TypeElement) ele;
				maps.put(classElement.getQualifiedName().toString(), fields = new ArrayList<VariableElement>());

			} else if (ele.getKind() == ElementKind.FIELD) // 判断该元素是否为成员变量
			{
				VariableElement varELe = (VariableElement) ele;
				// 获取该元素封装类型
				TypeElement enclosingElement = (TypeElement) varELe.getEnclosingElement();
				// 拿到key
				String key = enclosingElement.getQualifiedName().toString();
				fields = maps.get(key);
				if (fields == null) {
					maps.put(key, fields = new ArrayList<VariableElement>());
				}
				fields.add(varELe);
			}
		}

		for (String key : maps.keySet()) {
			if (maps.get(key).size() == 0) {
				TypeElement typeElement = elementUtils.getTypeElement(key);
				List<? extends Element> allMembers = elementUtils.getAllMembers(typeElement);
				if (allMembers.size() > 0) {
					maps.get(key).addAll(ElementFilter.fieldsIn(allMembers));
				}
			}
		}
		generateFile(maps);
		return true;
	}

	private void generateFile(Map<String, List<VariableElement>> maps) {
		File dir = new File(MyProcessor.class.getResource("/").getPath());
		if (!dir.exists())
			dir.mkdirs();
		// 遍历map
		for (String key : maps.keySet()) {

			// 创建文件
			File file = new File(dir, key.replaceAll("\\.", "_") + ".txt");
			try {
				/**
				 * 编写文件内容
				 */
				FileWriter fw = new FileWriter(file);
				fw.append("{").append("class:").append("\"" + key + "\"").append(",\n ");
				fw.append("fields:\n {\n");
				List<VariableElement> fields = maps.get(key);

				for (int i = 0; i < fields.size(); i++) {
					VariableElement field = fields.get(i);
					fw.append("  ").append(field.getSimpleName()).append(":")
							.append("\"" + field.asType().toString() + "\"");
					if (i < fields.size() - 1) {
						fw.append(",");
						fw.append("\n");
					}
				}
				fw.append("\n }\n");
				fw.append("}");
				fw.flush();
				fw.close();

			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}

	@Override
	public Set<String> getSupportedAnnotationTypes() {
		Set<String> set = super.getSupportedAnnotationTypes();
		if (set == null) {
			set = new HashSet<>();
		}
		set.add("com.robert.processor.Serialize");
		return set;
	}
}

我们经常使用的ButterKnife这个框架就很好的使用了AbstractProcessor

Butter Knife 是 Android 视图字段和方法绑定,使用注解处理来生成样板代码。后面做详细说明。


欢迎扫描二维码,关注个人公众号




Java注解处理器(Annotation Processor)详解 Java注解处理器是一个强大的工具,可以在编译时生成代码、验证API使用和提供元数据。通过与Google Auto Service结合,可以简化处理器的注册过程。注解处理器的主要优势在于它们可以在编译时捕获错误并生成高效的代码,避免运行时反射带来的性能开销。在实际应用中,注解处理器被广泛用于依赖注入框架、ORM映射、路由生成和序列化等场景,极大地提高了开发效率并减少了样板代码。 阅读详情

相关推荐

Java注解处理器APT

在JDK6的时候引入了JSR269的标准,即APT(Annotation Processing Tool),用于在编译时处理源代码中的注解,从而生成额外的代码、配置文件或其他资源。与传统的运行时反射相比,APT在编译时进行处理,可以提高性能并在编译阶段捕获一些问题,减少运行时错误。通过本文的详细介绍,读者对APT的概念、原理和应用应该有了更深入的理解。APT作为一个强大的编译时工具,可以帮助开发者实现自动化、提高代码质量和性能,并在项目开发中发挥重要作用。

架构大数据双料架构师的博客 465

Java中的注解处理器与编译时代码生成

Java中的注解处理器与编译时代码生成 大家好,我是微赚淘客系统3.0的小编,是个冬天不穿秋裤,天冷也要风度的程序猿! 注解处理器(Annotation Processor)是Java提供的一种强大工具,能够在编译期生成、验证和修改代码。它允许开发者通过注解和注解处理器在编译期执行一些特定的逻辑,比如生成代码、校验代码等。...

weixin_36790981的博客 262

版图提取的spice网表中参数含义及二级效应STI/WPE

寄生电阻、寄生电容可以从版图提出的.sp文件中看, ad area of drain 面积 as area of source pd perimeter of drain 周长,PS PD周长都不计算与栅极接触的部分 ps perimeter of source nrd 漏扩散区等效方块数 nrs 源扩散区等效方块数 sa ...

qq_40007892的博客 6552

利用编译时注解生成Java源代码

编译时注解开发

zhangquanit的专栏 5258

SPSS&Mplus—共同方法偏差(Common Method Bias)控制与检验

共同方法偏差(Common Method Bias)的控制方法:程序控制(Procedural)和统计控制(Statistical)。

m0_54401011的博客 1万+

告别安装报错!保姆级教程:用阿狸狗破戒大师V3.2.6搞定Cadence 17.4完整安装与补丁

本文提供Cadence 17.4的完整安装与破解教程,特别针对国内用户常见问题优化。从前期准备、镜像处理到阿狸狗破戒大师V3.2.6的智能破解,再到补丁管理与性能调优,详细指导每一步操作,确保一次性安装成功并提升设计效率。

weixin_30632089的博客 831

使用注解自动生成代码

如何使用注解来消除模板代码?关于 Annotation Processor 还有哪些你不知道的事...

GeeJoe 的博客 2181

ads设计Doherty功放(1)

Doherty功放的设计

qq_40995480的博客 2万+

java编译时生成代码,如何在Java运行时生成和编译源

如何在Java运行时生成和编译源使用ClassFactory,可以在运行时生成类,但是如果我们只需要编译源代码而无需加载它们或仅生成源代码,该怎么办呢?这是源代码生成器组件和Burningwave Core的JavaMemoryCompiler ,对我们有帮助。使用源代码生成器,我们可以生成源代码并将其存储在驱动器上,或者通过JavaMemoryCompiler对其进行编译。现在,让我们尝试生成并...

weixin_32440005的博客 887

手把手教你用Isograph Reliability Workbench 14.0绘制可靠性方框图(RBD)

本文详细介绍了如何使用Isograph Reliability Workbench 14.0绘制可靠性方框图(RBD),从软件安装、界面设置到基础项目创建和高级功能应用,手把手指导工程师完成系统可靠性分析。通过实际案例演示,帮助用户掌握RBD建模技巧,提升系统可靠性评估效率。

weixin_26765287的博客 619

闲鱼客户端三重动态签名机制解析:x-sign、x-mini-wua与x-umt

在移动客户端安全通信中,设备级动态签名已成为主流App防范自动化攻击的核心手段。其原理是将设备指纹、运行时行为与可信硬件标识深度融合,生成不可复用、不可跨端、不可静态伪造的请求凭证。这类机制超越传统Token或Session鉴权,具备强上下文绑定性与实时熵值校验能力,广泛应用于电商、社交及开放平台等高风险接口场景。技术价值体现在有效识别模拟器、无头浏览器与集群化爬虫,同时保障多端一致性与合规数据对接。本文聚焦闲鱼客户端实际落地的x-sign(带设备上下文的混合签名)、x-mini-wua(小程序行为水印)与

weixin_35732273的博客 495

java运行时自动生成代码_Java编译时注解自动生成代码

原文:http://blog.youkuaiyun.com/robertcpp/article/details/51628656经过测试即便生成文件也该是运行时才能生成。在开始之前,我们首先申明一个非常重要的问题:我们并不讨论那些在运行时(Runtime)通过反射机制运行处理的注解,而是讨论在编译时(Compile time)处理的注解。注解处理器是一个在javac中的,用来编译时扫描和处理的注解的工具。可以...

weixin_39915694的博客 678

【Unity3D框架】GameFramework框架完全教程《全网最全》-专栏文章目录

最近准备学习框架,了解到GameFramework框架是国产Unity3D框架,准备学习一下,但是奈何全网关于这个框架的教程实在太少。为了让自己学习方便一些,也为了让后来者乘凉。将框架以自己的理解整理目录,并且补全教程。觉得教程有帮助别忘了一键三连哦。

优快云博客专家,Unity3D高级软件工程师,《Unity 3D从入门到实战》作者。 2万+

Java中的编译时注解处理器

Java中的编译时注解处理器 大家好,我是微赚淘客系统3.0的小编,是个冬天不穿秋裤,天冷也要风度的程序猿!今天我们来深入探讨Java中的编译时注解处理器。编译时注解处理器是一种强大的工具,它允许开发者在编译期间对代码进行检查和处理,从而生成新的代码或资源。 什么是编译时注解处理器 编译时注解处理器(Annotation ...

weixin_31986143的博客 151

AgentScope Java 2.0 项目实战: 从零构建自己的个人AI助手“小龙虾“

本文系统介绍如何基于Spring Boot WebFlux、React 18和TypeScript,从零搭建一个本地化的个人AI助手管理平台——AgentScope Paw。项目支持多Agent创建与管理、SSE流式对话、工作区文件CRUD、技能市场、子智能体孵化、AI辅助起草Agent配置等核心功能,并深度集成钉钉、企业微信、飞书、GitHub等IM通道。

program哲学 1422

大中型超市收银系统(可直接运行)

光步前台收银系统系统功能:商品销售、商品退货、挂单、收银员权限、会员销售、单品取消、整单取消、商品查询、脱机销售、脱机数据上传,基本资料下载,开钱箱、小票打印、收款结算,支持多币种付款方式(现金、储值卡、礼券、微信等),支持多种促销。运行环境:.net 4.0登陆信息用户名:1001 密码:123456内置商品信息,商品编码可输入00001000 - 00010000,测试效果相关功能键F5 结算 F9挂单 F11商品查询 F8退货 Insert单品取消 Del整单取消 F12开钱箱F2 会员 Ctrl+Z退出系统 Home 锁屏 相关源码待公开

注解Annotation Processor学习

异常处理 Annotation processors must be explicitly declared now 在app的build中 android { ... defaultConfig { ... //添加如下配置就OK了 javaCompileOptions { annotationProcessorOpt...

乌龟赛跑 2383

VB摄像头监控

该VB模块可对摄像头捕获的画面进行录像等,可在创建的窗口进行控制

注解入门:反射+APT

一、什么是注解在我们写代码时,有时候会有一些配置信息,比如Spring里面的每个Service,最开始我们是在xml里面定义这些服务的名称和路径的,后来呢,觉得这些配置文件需要与Java源代码时刻同步,很容易写了一个服务后忘记在xml里面定义了。于是,就有了注解,通过直接给一个类加上表示它是Service的注解,就无需再去在xml里面定义它了,这样就只需要在一个地方维护这些信息就好了。其它部分所需...

eydwyz的专栏 992

LinePhone3.2.7(android端最新版本) sip客户端

SIP客户端For android:LinePhone3.2.7(最新版本),官网地址:http://www.linphone.org/

IDEA的使用指南

IDEA基于java的使用手册,可以最快速的上手,在使用中不断的丰富自己的使用技巧.

自定义一个注解

1.定义一个注解类/*** 自定义一个改变缓存的注解//改变数值 int changeValue() default 11;@Inherited:Java中的一个元注解(即可以用于注解其他注解的注解),用于指示被标记的注解是否可以被继承。当一个类使用了被@Inherited注解标记的注解时,其子类将自动继承该注解。具体来说,如果一个类使用了被@Inherited注解标记的注解A,在创建该类的子类时,子类也会自动继承该注解A。这样,通过在基类上使用注解,我们可以确保子类也具有相同的注解信息。

qq_40537587的博客 169

Android使用APT编译时注解生成代码

1.前言 最近在使用Butterknife的时候感觉它使用的注解挺有意思的,就了解一下,顺便自己花点时间实现一个类似的框架。加深对这块的理解,下面上干货。 2.注解 注解和class、interface一样属于一种类型。是在javaSE5.0后引入的概念。 注解通过关键字 @interface 进行定义: @Target(ElementType.FIELD) @Retention(Reten...

Red风信子的博客 277

详细的介绍一下java中的注解

通过Class对象的getAnnotation()、getDeclaredAnnotations()等方法,你可以获取到类、方法、变量等上的注解,并据此执行相应的操作。注解是Java中一种强大的工具,它允许你为代码添加额外的信息,这些信息可以在编译时或运行时被读取和处理。@Retention:指定注解的保留策略,包括SOURCE(源码时保留)、CLASS(编译时保留)和RUNTIME(运行时保留)。使用注解:在类、方法、变量等上面使用注解,并可以为其属性赋值。元注解是用于注解其他注解的注解。

优快云liuty的博客 736

Java 注解

前戏在 Java 语言中,注解是一种非常重要的组件,它允许在源代码中添加各种标记和元数据,在进行后续处理时使用这些标记和元数据,以提高程序的灵活性和可重用性。注解的使用注解可以用于修饰类、接口、字段、方法、参数、局部变量等元素,使用注解的格式为在元素前面加上 @ 符号。例如,一个注解可以这样定义:public @inter...

weixin_44772835的博客 98

Android-注解篇

1.什么是注解 ​ 从JDK 5 开始,Java 增加了注解,注解是代码里的特殊标记,这些标记可以在编译、类加载、运 行时被读取,并执行相应的处理。通过使用注解,开发人员可以在不改变原有逻辑的情况下, 在源文件中嵌入一些补充的信息。 2.注解的分类 注解包含:标准注解和元注解。 标准注解 @Override:对覆盖超类中的方法进行标记,如果被标记的方法并没有实际覆盖超类中 的方法,则编译器会发出错误警告。 @Deprecated:对不鼓励使用或者已过时的方法添加注解,当编程人员使用这些方法时, 将会

风的轨迹 1210

俯拾皆是的Java注解,你真的get了吗?

欢迎关注微信公众号:互联网全栈架构一、什么是注解注解是一种元数据,可以应用到代码的多种元素上,比如类、字段、方法等,它提供了关于这些元素的额外信息,但不会影响程序的运行逻辑。它主要有以下这些作用:为编译器提供额外信息:编译器可以用注解来检测错误、抑制警告等。比如注解@Override,如果被修饰的方法没有正确重写父类的方法,那么编译器就会报错。又比如@Deprecated,它用来标识一个方法已经过...

weixin_44742132的博客 157

Android进阶之自定义注解

原文链接:点击打开链接 本篇文章内容包括: 注解的概念元注解自定义注解Android自定义编译时注解 如果使用过ButterKnife, EventBus, Retrofit, Dagger等框架, 你对注解一定不会陌生. 但是注解背后究竟有什么魔法, 可以做这么不可思议的事情. 什么是注解 先来看看Java文档中的定义 An annotation is a form o

李牙刷儿的专栏 891

Java中注解的使用与原理

欢迎访问原文链接UML 注解语法 注解是由注解接口来定义的 modifiers @interface AnnotationName { elementDeclaration1; elementDeclaration1; } 每个元素的声明都有如下的形式: type elementName(); type elementname() default value; 我们从来不需要提供那些实现了注解接口的类,相反地,虚拟机会在需要的时候产生于血代理类和对象。 注解接口中的元素声明实际上是方法声明,

EJoft的博客 344

Java注解的入门学习

Java注解的入门学习

qinxun2008081的博客 794
上一篇: JAVA之代码混淆proguard
下一篇: android Cursor的自动管理方式
robert_chao
博客等级 码龄15年 265粉丝 119原创
评论 12
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值