Java中的APT的工作过程
Java中的APT的工作过程
APT即Annotatino Processing Tool, 他的作用是处理代码中的注解, 用来生成代码, 换句话说, 这是用代码生成代码的工具, 减少boilerplate代码.
我们通过一个简单的例子来简单APT的工作过程, 因为本文demo不设计ide及gradle等, 请注意包名及import问题.
根据上一篇博客Java中的自定义注解, 首先设计一个自定义注解MyAnnotation
.
package com.example;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.SOURCE) // 只保留到编译阶段
@Target(ElementType.TYPE) // 可用于类, 接口..
public @interface MyAnnotation {
}
下面来看一下我们的主角, Processor:
package com.example;
import javax.annotation.processing.AbstractProcessor;
import javax.annotation.processing.ProcessingEnvironment;
import javax.annotation.processing.RoundEnvironment;
import javax.lang.model.SourceVersion;
import javax.lang.model.element.TypeElement;
import java.util.HashSet;
import java.util.Set;
public class MyProcessor extends AbstractProcessor {
// Processor初始化回调
@Override
public synchronized void init(ProcessingEnvironment processingEnv) {
super.init(processingEnv);
System.out.println("MyProcessor init");
}
// processor处理过程的回调, 如果需要生成代码, 就在这个方法中写. 这个demo暂时不演示代码生成.
@Override
public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
System.out.println("process");
return false;
}
@Override
public Set<String> getSupportedAnnotationTypes() {
// 在此处声明该processor支持的注解类型
Set<String> set = new HashSet<>();
set.add(MyAnnotation.class.getCanonicalName());
return set;
}
@Override
public SourceVersion getSupportedSourceVersion() {
return SourceVersion.latestSupported();
}
}
那么我们如何把这个apt注册给javac呢? 我们将项目以常规的模式打包, 但是在META-INF目录中加入一个services
文件夹, 在其中创建一个名为javax.annotation.processing.Processor
的文件, 以文本将processor的完整名字写进去, 如果有多个processor, 换行即可.
javax.annotation.processing.Processor
的内容:
com.example.MyProcessor
最终jar包的结构:
mp.jar // jar包名字随意起
com
example
MyProcess.class
MyAnnotation.class
META-INF
services
javax.annotation.processing.Processor
MANIFEST.MF
测试
测试的例子很简单:
@MyAnnotation
public class Sample {
public static void main(String[] args) {
System.out.printf("Hello, World!");
}
}
我们用javac
编译这个文件
$ javac -cp mp.jar Sample.java
MyProcessor init
process
process
可以看到, 我们的Process已经生成了, 但是process过程输出了两次, 原因可以参考下图:
process
的过程会进行两边, 我们代码生成的过程应该在第一遍, 因为第二次processor的过程应当负责做一些清理的工作, 某些打包工具可能不会编译在第二阶段生成的.java源文件.
if (!roundEnv.processingOver()) { ... }
Java中的APT的工作过程的更多相关文章
- Java中的HashMap的工作原理是什么?
问答题23 /120 Java中的HashMap的工作原理是什么? 参考答案 Java中的HashMap是以键值对(key-value)的形式存储元素的.HashMap需要一个hash函数,它使用ha ...
- java中可定制的序列化过程 writeObject与readObject
来源于:[http://bluepopopo.iteye.com/blog/486548] 什么是writeObject 和readObject?可定制的序列化过程 这篇文章很直接,简单易懂.尝试着翻 ...
- Java中子类对象初始化的过程
Java中的继承机制看似简单,实际上包含了很多细节.最近在刷题过程中屡屡跳坑,于是自己仔细再学习了一下Java中子类初始化的细节,与大家分享. class Father { Father(){}; } ...
- Java中对象方法的调用过程&动态绑定(Dynamic Binding)
Java面向对象的最重要的一个特点就是多态, 而多态当中涉及到了一个重要的机制是动态绑定(Dynamic binding). 之前只有一个大概的概念, 没有深入去了解动态绑定的机理, 直到很多公司都问 ...
- Java中在时间戳计算的过程中遇到的数据溢出问题
背景 今天在跑定时任务的过程中,发现有一个任务在设置数据的查询时间范围异常,出现了开始时间戳比结束时间戳大的奇怪现象,计算时间戳的代码大致如下. package com.lingyejun.authe ...
- java中new一个对象的执行过程及类的加载顺序
1,new一个对象时代码的执行顺序 (1)加载父类(以下序号相同,表明初始化是按代码从上到下的顺序来的) 1.为父类的静态属性分配空间并赋于初值 1.执行父类静态初始化块; (2)加载子类 2.为子类 ...
- Java中传参的值传递和引用传递问题(转)
今天遇到了一个java程序,需要用参数来返回值(虽然最后用另一种方法实现了),在网上看到这样一篇文章,很受启发. 本文章来自于http://hi.baidu.com/xzhilie/blog/item ...
- 夯实Java基础系列13:深入理解Java中的泛型
目录 泛型概述 一个栗子 特性 泛型的使用方式 泛型类 泛型接口 泛型通配符 泛型方法 泛型方法的基本用法 类中的泛型方法 泛型方法与可变参数 静态方法与泛型 泛型方法总结 泛型上下边界 泛型常见面试 ...
- [转]Java中子类调用父类构造方法的问题分析
在Java中,子类的构造过程中,必须调用其父类的构造函数,是因为有继承关系存在时,子类要把父类的内容继承下来,通过什么手段做到的? 答案如下: 当你new一个子类对象的时候,必须首先要new一个 ...
随机推荐
- 九度oj 题目1060:完数VS盈数
题目1060:完数VS盈数 时间限制:1 秒 内存限制:32 兆 特殊判题:否 提交:6461 解决:2426 题目描述: 一个数如果恰好等于它的各因子(该数本身除外)子和,如:6=3+2+1.则称其 ...
- [luoguP1056] 排座椅(sort + 模拟)
传送门 nc题,一直sort就过了 代码 #include <cstdio> #include <iostream> #include <algorithm> #d ...
- poj 1456
#include<stdio.h> #include<string.h> #include<stdlib.h> #define N 10010 #define in ...
- bzoj 1430 小猴打架 prufer 性质
小猴打架 Time Limit: 5 Sec Memory Limit: 162 MBSubmit: 709 Solved: 512[Submit][Status][Discuss] Descri ...
- JS基础:函数
函数声明和函数表达式 在 JS 中定义函数的方式有两种:一种是函数声明,一种是函数表达式. 例如: //函数声明 function fun() { ... } //函数表达式 var f = func ...
- Ftp启动与关闭
//启动 service vsftpd start //关闭 service vsftpd stop 查看进程 ps -ef | grep ftp root : ? :: /usr/sbin/vsft ...
- IntentService用于服务中开启子线程的自动关闭
package com.pingyijinren.test; import android.app.IntentService; import android.content.Intent; impo ...
- 快速幂取模模板 && 51nod 1013 3的幂的和
#include <iostream> #include <cstdio> #include <cmath> #include <vector> #in ...
- Android GIS开发系列-- 入门季(13)Gdal简单写个shp文件
Gdal是用来读写栅格与矢量数据的,在Gdal官网,可以下载相关的资源进行平台的编译.其实Arcgis底层也是用Gdal来读取shp文件的,那在Android中可以直接读写shp文件吗,是可以的.这里 ...
- CentOS系统下Hadoop、Hbase、Zookeeper安装配置
近期给一个项目搭建linux下的大数据处理环境,系统是CentOS 6.3.主要是配置JDK.安装Tomcat,Hadoop.HBase和Zookeeper软件.博主在Hadoop这方面也是新手.配置 ...