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的工作过程的更多相关文章

  1. Java中的HashMap的工作原理是什么?

    问答题23 /120 Java中的HashMap的工作原理是什么? 参考答案 Java中的HashMap是以键值对(key-value)的形式存储元素的.HashMap需要一个hash函数,它使用ha ...

  2. java中可定制的序列化过程 writeObject与readObject

    来源于:[http://bluepopopo.iteye.com/blog/486548] 什么是writeObject 和readObject?可定制的序列化过程 这篇文章很直接,简单易懂.尝试着翻 ...

  3. Java中子类对象初始化的过程

    Java中的继承机制看似简单,实际上包含了很多细节.最近在刷题过程中屡屡跳坑,于是自己仔细再学习了一下Java中子类初始化的细节,与大家分享. class Father { Father(){}; } ...

  4. Java中对象方法的调用过程&动态绑定(Dynamic Binding)

    Java面向对象的最重要的一个特点就是多态, 而多态当中涉及到了一个重要的机制是动态绑定(Dynamic binding). 之前只有一个大概的概念, 没有深入去了解动态绑定的机理, 直到很多公司都问 ...

  5. Java中在时间戳计算的过程中遇到的数据溢出问题

    背景 今天在跑定时任务的过程中,发现有一个任务在设置数据的查询时间范围异常,出现了开始时间戳比结束时间戳大的奇怪现象,计算时间戳的代码大致如下. package com.lingyejun.authe ...

  6. java中new一个对象的执行过程及类的加载顺序

    1,new一个对象时代码的执行顺序 (1)加载父类(以下序号相同,表明初始化是按代码从上到下的顺序来的) 1.为父类的静态属性分配空间并赋于初值 1.执行父类静态初始化块; (2)加载子类 2.为子类 ...

  7. Java中传参的值传递和引用传递问题(转)

    今天遇到了一个java程序,需要用参数来返回值(虽然最后用另一种方法实现了),在网上看到这样一篇文章,很受启发. 本文章来自于http://hi.baidu.com/xzhilie/blog/item ...

  8. 夯实Java基础系列13:深入理解Java中的泛型

    目录 泛型概述 一个栗子 特性 泛型的使用方式 泛型类 泛型接口 泛型通配符 泛型方法 泛型方法的基本用法 类中的泛型方法 泛型方法与可变参数 静态方法与泛型 泛型方法总结 泛型上下边界 泛型常见面试 ...

  9. [转]Java中子类调用父类构造方法的问题分析

    在Java中,子类的构造过程中,必须调用其父类的构造函数,是因为有继承关系存在时,子类要把父类的内容继承下来,通过什么手段做到的? 答案如下:    当你new一个子类对象的时候,必须首先要new一个 ...

随机推荐

  1. 九度oj 题目1196:成绩排序

    题目1196:成绩排序 时间限制:1 秒 内存限制:32 兆 特殊判题:否 提交:5192 解决:1792 题目描述: 用一维数组存储学号和成绩,然后,按成绩排序输出. 输入: 输入第一行包括一个整数 ...

  2. hdu 5093 二分匹配

    /* 题意:给你一些冰岛.公共海域和浮冰,冰岛可以隔开两个公共海域,浮冰无影响 求选尽可能多的选一些公共海域点每行每列仅能选一个. 限制条件:冰山可以隔开这个限制条件.即*#*可以选两个 预处理: * ...

  3. 关于SQL SERVER导出数据的问题!

    前面一段时间,为这个导出数据真是煞费苦心,网上找了好多资料都没有找到. 从SQL SERVER 2008开始,我们就可以很方便的导出数据脚本,而无需再借助存储过程,但是SQL Server 2012和 ...

  4. dtrace.org

    http://dtrace.org/blogs/rm/2016/09/15/turtles-on-the-wire-understanding-how-the-os-uses-the-modern-n ...

  5. C++之类的比較运算符的重载

    比較运算符的重载通常有两种方式: 第一:作为成员函数重载 曾经几章的Student类为例: <span style="font-family:Microsoft YaHei;font- ...

  6. JAVA —— String is immutable. What exactly is the meaning? [duplicate]

    question: I wrote the following code on immutable Strings. public class ImmutableStrings { public st ...

  7. [React] Use Prop Collections with Render Props

    Sometimes you have common use cases that require common props to be applied to certain elements. You ...

  8. linux网络结构体

    一 链路层: (1)局域网(以太网ethernet): *struct eth_header:以太网头部. (ethernet/eth.c) *struct net_device:每一个网络设备都用这 ...

  9. Python 批量修改root密码

    #_*_coding:utf8_*_ from multiprocessing import Process, Pool import paramiko import sys,os host_list ...

  10. Java后端发出post请求带参数并接收返回的json

    核心代码: 参数格式: “key1=value1&key2=value2” /*** sendUrl    (远程请求的URL)* param    (远程请求参数)* JSONObject  ...