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 题目1196:成绩排序
			
题目1196:成绩排序 时间限制:1 秒 内存限制:32 兆 特殊判题:否 提交:5192 解决:1792 题目描述: 用一维数组存储学号和成绩,然后,按成绩排序输出. 输入: 输入第一行包括一个整数 ...
 - hdu  5093  二分匹配
			
/* 题意:给你一些冰岛.公共海域和浮冰,冰岛可以隔开两个公共海域,浮冰无影响 求选尽可能多的选一些公共海域点每行每列仅能选一个. 限制条件:冰山可以隔开这个限制条件.即*#*可以选两个 预处理: * ...
 - 关于SQL SERVER导出数据的问题!
			
前面一段时间,为这个导出数据真是煞费苦心,网上找了好多资料都没有找到. 从SQL SERVER 2008开始,我们就可以很方便的导出数据脚本,而无需再借助存储过程,但是SQL Server 2012和 ...
 - dtrace.org
			
http://dtrace.org/blogs/rm/2016/09/15/turtles-on-the-wire-understanding-how-the-os-uses-the-modern-n ...
 - C++之类的比較运算符的重载
			
比較运算符的重载通常有两种方式: 第一:作为成员函数重载 曾经几章的Student类为例: <span style="font-family:Microsoft YaHei;font- ...
 - JAVA —— String is immutable. What exactly is the meaning? [duplicate]
			
question: I wrote the following code on immutable Strings. public class ImmutableStrings { public st ...
 - [React] Use Prop Collections with Render Props
			
Sometimes you have common use cases that require common props to be applied to certain elements. You ...
 - linux网络结构体
			
一 链路层: (1)局域网(以太网ethernet): *struct eth_header:以太网头部. (ethernet/eth.c) *struct net_device:每一个网络设备都用这 ...
 - Python 批量修改root密码
			
#_*_coding:utf8_*_ from multiprocessing import Process, Pool import paramiko import sys,os host_list ...
 - Java后端发出post请求带参数并接收返回的json
			
核心代码: 参数格式: “key1=value1&key2=value2” /*** sendUrl (远程请求的URL)* param (远程请求参数)* JSONObject ...