久久精品人人爽,华人av在线,亚洲性视频网站,欧美专区一二三

Annotation Processor 處理器問題如何深度定位

157次閱讀
沒有評論

共計 5980 個字符,預(yù)計需要花費 15 分鐘才能閱讀完成。

Annotation Processor 處理器問題如何深度定位,針對這個問題,這篇文章詳細介紹了相對應(yīng)的分析和解答,希望可以幫助更多想解決這個問題的小伙伴找到更簡單易行的方法。

什么是 Annotation Processor 構(gòu)建問題

寫過自定義注解處理器的老司機們乍一看這個問題覺得挺簡單,是的,因為網(wǎng)上基本通篇都在教你怎么打日志,但是你有沒有想過如果連日志都打印不出來的時候你怎么定位呢? 譬如如下代碼:

//  確認  META-INF/services/javax.annotation.processing.Processor  沒問題  //  確認構(gòu)建腳本沒問題,確認注解  Bridge  有被使用且有參與構(gòu)建  @AutoService(Processor.class) public class TestAnnotationProcessor extends AbstractProcessor { public TestAnnotationProcessor() { System.out.println( TestAnnotationProcessor constrator  } @Override public synchronized void init(ProcessingEnvironment processingEnvironment) { super.init(processingEnvironment); System.out.println(TestAnnotationProcessor init  } @Override public Set String  getSupportedAnnotationTypes() { System.out.println( TestAnnotationProcessor getSupportedAnnotationTypes  Set String  supported = new HashSet String  supported.add(Bridge.class.getCanonicalName()); return supported; } @Override public boolean process(Set ? extends TypeElement  set, RoundEnvironment roundEnvironment) { System.out.println( TestAnnotationProcessor process  return true; } }

運行構(gòu)建后 compileReleaseJavaWithJavac 過程中沒有先吐我 Annotation Processor   的任意一行日志,直接報錯找不到我注解處理器產(chǎn)物類引用(即直接進行了 compile class 環(huán)節(jié))。

你懵逼嗎? 反正我懵逼了! 打印日志不好使了,哈哈,環(huán)境確認沒問題,什么鬼,直接越過 Annotation Processor 進行 compile   了。

這時候就需要你稍微深入定位分析(擼 javac 源碼的巨佬請自行飄過),前提就是你需要熟悉下 Annotation Processor   基本原理,然后我們通過一些額外的 javac 詳細日志進行舉例分析。

Annotation Processor 機制

注解和注解處理器是 JDK5 引入的機制,主要用來為類、方法、字段和參數(shù)等 Java 結(jié)構(gòu)提供額外的信息。譬如常見的 @Override 就是僅僅對 Java   編譯器生效的一個注解。Java   允許我們自定義注解,自定義的注解處理器就是用來處理這些自定義注解的(廢話),注解處理器觸發(fā)時機是由 javac 來處理的,所以整個 javac 過程的簡要步驟如下圖:

javac 主要步驟

可以看到,javac 編譯概要圖主要分為如下幾步:

把源文件解析為抽象語法樹。

調(diào)用已注冊的注解處理器。

如果注解處理器處理過程中生成了新的源文件,編譯器重復(fù)第 1、2 步,當注解處理器不再生成新的源文件則進入最后一輪。

進入真正的 compile 字節(jié)碼環(huán)節(jié)生成字節(jié)碼。

如上就是注解處理器的核心機制,有了這個核心機制的認識我們就繼續(xù)往下探索。

構(gòu)建工具下 Annotation Processor 的本質(zhì)

我們?nèi)粘i_發(fā)中 (無論是 Java 后端還是 Android 移動端) 總是多多少少會用到 JDK 提供的 annotation  processor 能力,無論是什么構(gòu)建工具 (Gradle 或者 Maven 等) 本質(zhì)都是通過 javac -processorpath 命令參數(shù)顯式指定哪些  Processer,或者顯式聲明 META-INF/services/javax.annotation.processing.Processor 來被 javac 發(fā)現(xiàn)并調(diào)用的(參見  google 的 AutoService 框架)。

正常情況下我們開發(fā)中使用及構(gòu)建 Annotation Processor 技術(shù)都是上面幾步走的方案,而且大多數(shù)照著網(wǎng)絡(luò)上抄的都能正常工作,每次只用自己處理  process 就挺香的,因為只要按照規(guī)則聲明放置,其他的 javac 都能自己完美調(diào)用。

增強 javac 過程打印暴露問題

要解決一開始說的 Annotation Processor   中自己加的日志都不打印場景問題,我們需要獲取一些額外的信息輔助定位。由于直接使用命令行 javac 的方式是最原始的操作,我們構(gòu)建一般采用 Gradle,而  Gradle 的本質(zhì)還是調(diào)用 javac,所以下面我們以 Gradle 為例來分析如何定位 Annotation Processor 問題。

下面簡單粗暴點就是直接在根目錄的 build.gradle 中給所有模塊添加參數(shù):

//  參數(shù)可選,重點是  -verbose -XprintRounds -XprintProcessorInfo allprojects { gradle.projectsEvaluated { tasks.withType(JavaCompile) { options.compilerArgs    -Xlint     -verbose     -XprintRounds     -XprintProcessorInfo     -Xmaxerrs     100000  } } }

你也可以僅僅在自己有注解處理器的模塊中添加,與上面一樣,只要加給 JavaCompile 的參數(shù)就行。這里的參數(shù)其實就是我們平時命令行 javac 是否的參數(shù),不懂的可以去命令行執(zhí)行下 javac  -help 觀摩下含義吧,如下(JDK8,不同版本 JDK 略有差異):

yan@yanDeMackbookPro:~$ javac -help  用法: javac  options   source files   其中,  可能的選項包括: -g  生成所有調(diào)試信息  ...... -verbose  輸出有關(guān)編譯器正在執(zhí)行的操作的消息  ...... -processor  class1 [, class2 , class3 ...]  要運行的注釋處理程序的名稱;  繞過默認的搜索進程  -processorpath  路徑   指定查找注釋處理程序的位置  ......

至于腳本中其他幾個在 javac  -help 中沒有的參數(shù)可以看下官方文檔 https://docs.oracle.com/en/java/javase/11/tools/javac.html  ,里面詳細解釋了參數(shù)含義。

添加上面參數(shù)后一定要將你的構(gòu)建日志追加到一個磁盤文件中,因為日志會變得非常龐大,同時也變得很容易定位問題。

通過構(gòu)建日志分析定位問題

執(zhí)行你的構(gòu)建任務(wù),完畢后分析定位主要分為如下幾個步驟,每一步都是一種場景的定位,循序漸進定位分析即可。

1. 在你的日志中搜索你的 Processor 類名,譬如 TestAnnotationProcessor.class,看到的日志會是如下。

//  如果你的注解處理器在項目中是源碼形式的日志  [loading RegularFileObject[/home/user/yan/test/target/classes/cn/yan/test/TestAnnotationProcessor.class]] //  如果你的注解處理器在項目中是依賴  jar  形式的日志  [loading ZipFileIndexFileObject[....../test.jar(cn/yan/test/TestAnnotationProcessor.class)]]

分析:如果你的日志中搜不到上面信息,說明你的注解處理器沒有被添加到 javac 的 classpath   中。一般問題就是你的 META-INF/services/javax.annotation.processing.Processor 聲明有問題,javac 無法找到你的注解處理器。有些同學(xué)可能是通過  google 的 AutoService   來生成 META-INF/services/javax.annotation.processing.Processor 的,這種情況下也要自己檢查是否  OK(譬如之前安卓中 AGP 有一段時間的中間過渡版本就修改了 classpath,需要手動將 compile 改成 annotationProcessor   才行)。

2. 在你的日志中搜索 Round 關(guān)鍵字,建議直接搜 Round 1: 這樣的格式容易點,看到的日志會是如下。

Round 1: input files: {cn.yan.test.Application, ......, cn.yan.test.UseMarkedAnnotation} annotations: [java.lang.Override, cn.yan.annotation.Bridge] last round: false

上面日志中的 input  files: 部分是掃到的你的源碼,annotations: 部分就是掃到你代碼中使用了哪些注解,如果你注解處理器聲明了要處理這種注解(譬如 @cn.yan.annotation.Bridge),則日志如上才是正常的。

分析:  如果你日志中沒搜到上面的 Round,則說明 javac 沒有觸發(fā)調(diào)用任何注解處理器(無論是你寫的還是依賴三方框架的),最大的可疑點就是檢查下自己有沒有禁用 javac 注解處理器,也就是確認 javac 執(zhí)行時沒有 -proc:none 參數(shù)。如果你的日志中有 Round,但是 input  files: 和 annotations: 沒有你的注解類和使用類,則說明你沒有在代碼中使用你注解處理器要處理的注解。

3. 在你的日志中搜索 Loaded cn.yan.test.TestAnnotationProcessor 關(guān)鍵字,看到的日志會是如下。

[Loaded cn.yan.test.TestAnnotationProcessor from file:/home/user/yan/test/target/classes/cn/yan/test/TestAnnotationProcessor.class]

分析:  如果你看不到上面這行日志,說明你的注解處理器類自己沒有被加載成功,為什么沒有我也不知道怎么分析了,但是至少說明沒加載成功,你可能需要仔細核對哪里不規(guī)范或者不合法導(dǎo)致的了。

上面都排查完了,如果還是找不到問題原因,不妨換個思路,去仔細檢查下你參與構(gòu)建的普通 java   文件,是否存在語法錯誤或者什么問題(譬如常量沒聲明等); 如果有,解決完了再試試,別問我為什么,我也沒有深入研究 javac 這塊源碼,只是我遇到過,且也沒有異常堆棧信息,最終發(fā)現(xiàn)是合并解決沖突后代碼少了一個變量聲明,就是單純的越過了  Annotation Processor 過程直接進行 compile to class 流程了)。

這個技能有什么鳥用?

不瞞你說,我也算是老司機了,好些年前 Annotation Processor 就玩的很 6 了,但是最近項目升級構(gòu)建和 Java8 及 androidX   支持后 merge 了下代碼,然后項目中的注解處理器、dataBinding   全部都不工作了,更可氣的是,這個不工作是真的很吝嗇,什么錯誤堆棧都沒有,大致如下奇葩構(gòu)建日志:

FAILURE: Build failed with an exception. * What went wrong: Execution failed for task  :test:compileReleaseJavaWithJavac . //  本來這里該先吐我注解處理器內(nèi)部的日志,然后才繼續(xù)  javac  編譯,實際什么都沒吐    Compilation failed; see the compiler error output for details. * Exception is: org.gradle.api.tasks.TaskExecutionException: Execution failed for task  :moffice:compileReleaseJavaWithJavac . at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.lambda$executeIfValid$1(ExecuteActionsTaskExecuter.java:200) ...... Caused by: org.gradle.api.internal.tasks.compile.CompilationFailedException: Compilation failed; see the compiler error output for details. at org.gradle.api.internal.tasks.compile.JdkJavaCompiler.execute(JdkJavaCompiler.java:57)

Gradle   構(gòu)建命令已經(jīng)添加了各種詳細參數(shù)供查看堆棧和詳細日志,但奇妙的事情就是他走到 compileReleaseJavaWithJavac 就直接出錯了,前后沒有任何錯誤提示(有的只是一坨  Gradle 自己的 task 調(diào)用鏈)。我特么大意了,我就同步了下代碼,編不過就編不過啊,你倒是提示下問題啊! 啥也不提示直接干到 compile class   環(huán)節(jié)了,跳過了 Annotation Processor 流程,這就很惱火了。好在按照上面方式定位修復(fù)了,哈哈。

關(guān)于 Annotation Processor 處理器問題如何深度定位問題的解答就分享到這里了,希望以上內(nèi)容可以對大家有一定的幫助,如果你還有很多疑惑沒有解開,可以關(guān)注丸趣 TV 行業(yè)資訊頻道了解更多相關(guān)知識。

正文完
 
丸趣
版權(quán)聲明:本站原創(chuàng)文章,由 丸趣 2023-08-04發(fā)表,共計5980字。
轉(zhuǎn)載說明:除特殊說明外本站除技術(shù)相關(guān)以外文章皆由網(wǎng)絡(luò)搜集發(fā)布,轉(zhuǎn)載請注明出處。
評論(沒有評論)
主站蜘蛛池模板: 广汉市| 嫩江县| 桑植县| 嘉荫县| 乐昌市| 兴文县| 渭源县| 普格县| 南昌市| 子长县| 准格尔旗| 瑞昌市| 卓尼县| 楚雄市| 从江县| 于田县| 新平| 浦江县| 东宁县| 师宗县| 沧州市| 七台河市| 蓬溪县| 镇安县| 横山县| 西平县| 宁南县| 栖霞市| 沧州市| 平利县| 金坛市| 上犹县| 合肥市| 和静县| 景洪市| 青冈县| 团风县| 抚州市| 蓬溪县| 金沙县| 淮南市|