如何处理Java注释
Java 8的很酷的新功能之一就是對(duì)lambda表達(dá)式的支持。 Lambda表達(dá)式在很大程度上依賴于FunctionalInterface 注釋 。
在本文中,我們將介紹注釋以及如何處理它們,以便您可以實(shí)現(xiàn)自己的出色功能。
注解
Java 5中添加了注釋 。Java語言附帶了一些預(yù)定義的注釋 ,但是您也可以定義自定義注釋 。
許多框架和庫都充分利用了自定義注釋。 例如, JAX-RS使用它們將POJO轉(zhuǎn)換為REST資源。
注釋可以在編譯時(shí)或在運(yùn)行時(shí)(或什至兩者)進(jìn)行處理。
在運(yùn)行時(shí),您可以使用反射API 。 可以注釋的Java語言的每個(gè)元素(例如類或方法)都實(shí)現(xiàn)AnnotatedElement接口。 請(qǐng)注意,只有具有RUNTIME RetentionPolicy的注釋才可以在運(yùn)行時(shí)RUNTIME 。
編譯時(shí)注釋處理
Java 5帶有單獨(dú)的apt工具來處理注釋,但是自Java 6起,此功能已集成到編譯器中。
您可以直接從命令行調(diào)用編譯器,例如從命令行調(diào)用,也可以從程序間接調(diào)用。
在前一種情況下,您可以為javac指定-processor選項(xiàng) ,或者通過將文件META-INF/services/javax.annotation.processing.Processor到j(luò)ar META-INF/services/javax.annotation.processing.Processor來使用ServiceLoader框架。 該文件的內(nèi)容應(yīng)為一行,其中包含處理器類的完全限定名稱。
ServiceLoader方法在自動(dòng)構(gòu)建中特別方便,因?yàn)槟龅木褪窃诰幾g過程中將注釋處理器放在類路徑上,而Maven或Gradle之類的構(gòu)建工具將為您提供幫助。
從應(yīng)用程序內(nèi)部進(jìn)行編譯時(shí)注釋處理
您還可以使用編譯時(shí)工具從正在運(yùn)行的應(yīng)用程序中處理注釋。
與其直接調(diào)用javac ,不如使用更方便的JavaCompiler接口。 無論哪種方式,您都需要使用JDK而不是JRE運(yùn)行應(yīng)用程序。
JavaCompiler接口使您能夠以編程方式訪問Java編譯器。 您可以使用ToolProvider.getSystemJavaCompiler()獲得此接口的實(shí)現(xiàn)。 此方法對(duì)JAVA_HOME環(huán)境變量敏感。
JavaCompiler的getTask()方法允許您添加注釋處理器實(shí)例 。 這是控制注釋處理器構(gòu)造的唯一方法。 調(diào)用注釋處理器的所有其他方法都要求處理器具有公共的無參數(shù)構(gòu)造函數(shù)。
注釋處理器
處理器必須實(shí)現(xiàn)Processor接口。 通常,您將要擴(kuò)展AbstractProcessor基類,而不是從頭開始實(shí)現(xiàn)接口。
每個(gè)注釋處理器必須通過getSupportedAnnotationTypes()方法指示其感興趣的注釋類型。 您可以返回*以處理所有注釋。
另一個(gè)重要的事情是指出您支持的Java語言版本。 重寫getSupportedSourceVersion()方法并返回RELEASE_x常量之一。
通過實(shí)現(xiàn)這些方法,注釋處理器就可以開始工作了。 處理器的作用在process()方法中。
當(dāng)process()返回true ,處理的注釋被這個(gè)處理器權(quán)利 ,并且將不被提供給其它處理器。 通常,您應(yīng)該與其他處理器配合使用并返回false 。
元素和類型鏡
注釋和它們所在的Java元素作為Element對(duì)象提供給您的process()方法。 您可能需要使用Visitor模式處理它們 。
最有趣的元素類型是用于類和接口(包括注釋)的TypeElement ,用于方法的ExecutableElement和用于字段的VariableElement 。
每個(gè)Element指向一個(gè)TypeMirror ,它表示Java編程語言中的一個(gè)類型。 您可以使用TypeMirror來遍歷正在處理的帶注釋的代碼的類關(guān)系,就像在JVM中運(yùn)行的代碼上使用反射一樣。
加工回合
注釋處理發(fā)生在稱為rounds的單獨(dú)階段中。 在每個(gè)回合中,處理器都有機(jī)會(huì)處理其感興趣的注釋。
可通過傳遞到process()方法中的RoundEnvironment參數(shù)獲得要處理的注釋及其上存在的元素。
如果注釋處理器在一輪中生成新的源文件或類文件,則編譯器將使這些文件可用于下一輪處理。 這將繼續(xù),直到不再生成新文件為止。
最后一輪不包含任何輸入,因此是釋放處理器可能已獲取的任何資源的好機(jī)會(huì)。
初始化和配置處理器
注釋處理器使用ProcessingEnvironment 初始化 。 此處理環(huán)境使您可以創(chuàng)建新的源文件或類文件 。
它還以選項(xiàng)的形式提供對(duì)配置的訪問。 選項(xiàng)是鍵值對(duì),您可以使用-A option在命令行上提供給javac 。 為此,必須在處理器的getSupportedOptions()方法中返回選項(xiàng)的鍵。
最后,處理環(huán)境提供了一些在處理過程中派上用場(chǎng)的支持例程(例如, 獲取元素的JavaDoc或獲取類型的直接超類型 )。
類路徑問題
為了在注釋處理過程中獲得最準(zhǔn)確的信息,您必須確保所有導(dǎo)入的類都在類路徑上,因?yàn)橐貌豢捎妙愋偷念惪赡芫哂胁煌暾男畔⒒蛲耆鄙傩畔ⅰ?
當(dāng)處理大量帶注釋的類時(shí),這可能會(huì)在Windows系統(tǒng)上導(dǎo)致命令行太大 (> 8K)的問題。 即使使用JavaCompiler接口,它仍會(huì)在后臺(tái)調(diào)用javac 。
Java編譯器有一個(gè)很好的解決方案:您可以使用包含javac 參數(shù)的參數(shù)文件 。 然后,在命令行上提供參數(shù)文件的名稱,并在@之前。
不幸的是, JavaCompiler.getTask()方法不支持參數(shù)文件,因此您必須使用基礎(chǔ)的run()方法。
請(qǐng)記住, getTask()方法是唯一一種允許您構(gòu)造注釋處理器的方法。 如果必須使用參數(shù)文件,則必須使用公共的無參數(shù)構(gòu)造函數(shù)。
如果遇到這種情況,并且有多個(gè)注釋處理器需要共享一個(gè)類的單個(gè)實(shí)例,則無法將該實(shí)例傳遞到構(gòu)造函數(shù)中,因此將被迫使用諸如Singleton模式之類的東西。
結(jié)論
注釋是一項(xiàng)令人興奮的技術(shù),具有許多有趣的應(yīng)用程序。 例如,我使用它們將REST API中的資源提取到資源模型中以進(jìn)行進(jìn)一步處理,例如生成文檔。
翻譯自: https://www.javacodegeeks.com/2015/01/how-to-process-java-annotations.html
總結(jié)
以上是生活随笔為你收集整理的如何处理Java注释的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 安卓写程序软件(安卓写程序)
- 下一篇: 玩Java并发