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()) { ... }

原文地址:https://www.cnblogs.com/fortitude/p/10936386.html

时间: 2024-12-14 20:16:32

Java中的APT的工作过程的相关文章

JAVA中对象创建和初始化过程

1.Java中的数据类型 Java中有3个数据类型:基本数据类型(在Java中,boolean.byte.short.int.long.char.float.double这八种是基本数据类型).引用类型和null类型.其中,引用类型包括类类型(含数组).接口类型. 下列语句声明了一些变量: 以下是引用片段: int k ;  A a; //a是A数据类型的对象变量名.  B b1,b2,-,b10000;// 假定B是抽象类或接口.  String s; 注意:从数据类型与变量的角度看,基本数据

【转载】Java中System.loadLibrary() 的执行过程

最近复习JNI,通过AndroidStudio导入源码一点点的跟踪分析so库的加载过程. 在网上发现有其他同学做了同样的工作,对比文章看起来更加轻松.感谢他们的工作!下面是其中比较好的一篇的转载. 原文链接:http://my.oschina.net/wolfcs/blog/129696 未经许可转载,如有侵权,请联系我删除. 目录[-] 系统的library path Native 层load library的过程 System.loadLibrary()是我们在使用Java的JNI机制时,会

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

目录 泛型概述 一个栗子 特性 泛型的使用方式 泛型类 泛型接口 泛型通配符 泛型方法 泛型方法的基本用法 类中的泛型方法 泛型方法与可变参数 静态方法与泛型 泛型方法总结 泛型上下边界 泛型常见面试题 参考文章 微信公众号 Java技术江湖 个人公众号:黄小斜 本系列文章将整理到我在GitHub上的<Java面试指南>仓库,更多精彩内容请到我的仓库里查看 https://github.com/h2pl/Java-Tutorial 喜欢的话麻烦点下Star.Fork.Watch三连哈,感谢你的

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

在Java中,子类的构造过程中,必须调用其父类的构造函数,是因为有继承关系存在时,子类要把父类的内容继承下来,通过什么手段做到的? 答案如下:    当你new一个子类对象的时候,必须首先要new一个父类的对像出来,这个父类对象位于子类对象的内部,所以说,子类对象比父类对象大,子类对象里面包含了一个父类的对象,这是内存中真实的情况.构造方法是new一个对象的时候,必须要调的方法,这是规定,要new父类对象出来,那么肯定要调用其构造方法,所以: 第一个规则:子类的构造过程中,必须调用其父类的构造方

JAVA中voltatile关键字的使用

1.首先要明白一个概念 JAVA中主内存和线程工作内存的概念. 如果有一个static的变量,值会存储在主内存.如果多个线程访问这个变量,每个线程都会将变量的值拷贝到自己的工作内存,之后的操作就是针对自己工作内存里副本的操作,最后再写回主内存 明显,上面的操作非原子操作,会出现经典的多线程问题: 变量 i=6,线程A和B都对i进行加1操作,期待i为8,但是: 线程A访问 i, 线程A进行 i++操作 线程B访问 i, 线程B进行 i++操作 线程A更新i,i为7 线程B更新i,i为7 2. vo

HTTP协议报文、工作原理及Java中的HTTP通信技术详解

一.web及网络基础       1.HTTP的历史            1.1.HTTP的概念:                 HTTP(Hyper Text Transfer Protocol,超文本传输协议)是一种通信协议,它允许将超文本标记语言(HTML)文档从Web服务器传送到客户端的浏览器.                 它是一个应用层协议,承载于TCP之上.由请求和响应构成,是一个标准的客户端服务器模型            1.2.HTTP的发展历史:          

哈希表工作原理 (并不特指Java中的HashTable)

1. 引言         哈希表(Hash Table)的应用近两年才在NOI中出现,作为一种高效的数据结构,它正在竞赛中发挥着越来越重要的作用.  哈希表最大的优点,就是把数据的存储和查找消耗的时间大大降低,几乎可以看成是常数时间:而代价仅仅是消耗比较多的内存.然而在当前可利用内存越来越多的情况下,用空间换时间的做法是值得的.另外,编码比较容易也是它的特点之一.         哈希表又叫做散列表,分为“开散列” 和“闭散列”.考虑到竞赛时多数人通常避免使用动态存储结构,本文中的“哈希表”仅

【转】Java学习---解析Java Servlet工作过程

[原文]https://www.toutiao.com/i6594316694657696264/ 解析Java Servlet工作过程 Servlet简介 Servlet是sun公司提供的一门用于开发动态web资源的技术. Sun公司在其API中提供了一个servlet接口,用户若想用发一个动态web资源(即开发一个Java程序向浏览器输出数据),需要完成以下2个步骤: 编写一个Java类,实现servlet接口. 把开发好的Java类部署到web服务器中. Servlet的运行过程 Serv

【java】java中的注解(Annotation)是如何工作的?

Java中的注解是如何工作的? 自Java5.0版本引入注解之后,它就成为了Java平台中非常重要的一部分.开发过程中,我们也时常在应用代码中会看到诸如@Override,@Deprecated这样的注解.这篇文章中,我将向大家讲述到底什么是注解,为什么要引入注解,注解是如何工作的,如何编写自定义的注解(通过例子),什么情况下可以使用注解以及最新注解和ADF(应用开发框架).这会花点儿时间,所以为自己准备一杯咖啡,让我们来进入注解的世界吧. 什么是注解? 用一个词就可以描述注解,那就是元数据,即