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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM