記一次注解處理器的開發過程


需求描述

開發一個掃描所有注解信息的腳本程序,希望在編譯期對代碼進行掃描,如果注解書寫不規范則使編譯失敗。

本次的需求剛好用AbstractProcessor可以滿足,在這次需求中我學習到了注解處理器的開發,並且踩了一些坑,在這里記錄下來,希望能夠幫助其他人在開發的時候避免。

AbstractProcessor

簡介

我們在網上搜索到的AbstractProcessor,大多用於Android開發時用到,但實際上注解處理器在我們的工作中仍然也能起到很大的作用。

注解的處理除了可以在運行時通過反射機制處理外,還可以在編譯期進行處理。在編譯期處理注解時,會處理到不再產生新的源文件為止,之后再對所有源文件進行編譯。

Java5中提供了apt工具來進行編譯期的注解處理。apt是命令行工具,與之配套的是一套描述“程序在編譯時刻的靜態結構”的API:Mirror API(com.sun.mirror.*)。通過Mirror API可以獲取到被注解的Java類型元素的信息,從而提供自定義的處理邏輯。具體的處理工具交給apt來處理。編寫注解處理器的核心是兩個類:注解處理器(com.sun.mirror.apt.AnnotationProcessor)、注解處理器工廠(com.sun.mirror.apt.AnnotationProcessorFactory)。apt工具在完成注解處理后,會自動調用javac來編譯處理完成后的源代碼。然而,apt工具是oracle提供的私有實現(在JDK開發包的類庫中是不存在的)。在 Java8中,已經移除了 APT 工具;在JDK6中,將注解處理器這一功能進行了規范化,形成了java.annotation.processing的API包,Mirror API則進行封裝,形成javax.lang.model包。注解處理器的開發進行了簡化,不再單獨使用apt工具,而將此功能集成到了javac命令中。(當前開發使用的JDK版本一般都在6以上,故對apt工具不做研究)。

簡單來講,就是 我們可以通過使用 AbstractProcessor 可以在編譯期處理所有指定的注解。

AbstractProcessor,是一個抽象類,該類實現了接口Processor。處理接口提供了一個核心處理方法process(),用於開發者實現自己的處理邏輯(用於處理先前round中產生的注解)。

boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv);

process()方法有一個boolean類型的返回值,若返回false,表示本輪注解未聲明並且可能要求后續其它的Processor處理它們;若返回true,則代表這些注解已經聲明並且不要求后續Processor來處理它們。

開發

我們暫時不需要考慮其他方法的實現,這些操作我們也不需要,我們只需要指定需要處理的注解,指定編譯的Java版本,並且實現核心邏輯process()方法就可以了。

@SupportedAnnotationTypes({"XXX"})//指定注解的類型
@SupportedSourceVersion(SourceVersion.RELEASE_8)//指定支持的Java版本,這里是Java8
public class VUAnnotationProcessor extends AbstractProcessor {

  
  	// annotations為要求處理的注解類型
  	// roundEnv 中包含了當前和上一輪的環境信息,從中我們可以獲取掃描出來的注解實例
    @Override
    public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
      //在這里書寫處理邏輯
        return true;
    }
}

聲明

這些開發完了之后,我們需要在resources目錄下創建META-INF/services目錄,在其下創建javax.annotation.processing.Processor文件,並在其中填寫我們自定義的注解處理器的全類名。

坑:服務配置文件不正確

我們在開發完進行編譯,很快會在控制台發現這行錯誤

錯誤: 服務配置文件不正確, 或構造處理程序對象javax.annotation.processing.Processor: XXX could not be instantiated: java.lang.NoClassDefFoundError: XXX 時拋出異常錯誤

為什么呢?因為注解處理器在啟動的時候,注解處理器本身還沒有編譯,所以找不到。WTF。

那么,同學們,怎么才能解決這個“雞生蛋,蛋生雞”的問題呢?

第一,把這個類拆到單獨的Jar包里面,不要讓它干擾到需要掃描的項目里。

第二,在這個單獨的項目里,引入聲明,表示,這個項目不要用注解處理器掃描。

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>2.0.2</version>
                <executions>
                    <execution>
                        <id>default-compile</id>
                        <configuration>
                            <compilerArgument>-proc:none</compilerArgument>
                            <source>1.8</source>
                            <target>1.8</target>
                        </configuration>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>

這樣才能讓這個類編譯成功,並且讓它在其他項目編譯的時候生效。

參考

https://blog.zenfery.cc/archives/78.html


免責聲明!

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



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