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