Java編譯器API簡介

今天給你們分享的是Java編譯器API簡介,文章部份內容摘自【優銳課】學習筆記。java

Java編譯器API

Java編譯器API是Java模塊(稱爲java.compiler)的一部分。該模塊包括語言模型和註釋處理,以及編譯器API。它定義了Java編程語言和編譯器工具的類型和模型聲明,能夠在執行期間從應用程序代碼中調用它們。註釋處理有助於訪問註釋處理器,能夠將其視爲Java編譯器的插件。它使註釋處理器和註釋處理工具環境之間可以通訊。模型,元素和類型包處理Java編程語言的元素,而util包則幫助處理程序元素和類型。編程

編譯工具

javax.tools包提供了與Java編譯器一塊兒使用的接口和類,而且能夠在執行期間從程序中調用它。 它提供了一個框架,該框架容許客戶端從其本身的應用程序代碼定位和運行編譯器。它還提供了服務提供者接口(SPI),用於對診斷的結構化訪問和用於覆蓋文件訪問的文件抽象。ToolProvider類提供了編譯器API的入口點。此類提供了一些方法來定位編譯器的工具提供者。 例如,咱們能夠輕鬆地找到系統中安裝的編譯器支持的Java源版本列表。api

1 JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
2 for(SourceVersion sv:compiler.getSourceVersions()){
3    System.out.println(sv);
4 }

 

輸出以下(根據系統中安裝的版本)。框架

1 RELEASE_3
2 RELEASE_4
3 RELEASE_5
4 RELEASE_6
5 RELEASE_7
6 RELEASE_8
7 RELEASE_9
8 RELEASE_10
9 RELEASE_11

 

在這種狀況下,ToolProvider會找到默認的編譯器。經過使用服務提供者機制,還能夠找到替代的編譯器或工具。若是某些供應商提供Java編譯器,則jar文件將包含文件META-INF / service / javax.tool.JavaCompiler,而且將包含一行:com.vendor.VendorJavaCompiler。咱們能夠將jar文件放入類路徑中,並按如下方式定位它:dom

1 JavaCompiler vendorJavaCompiler =
2    ServiceLoader.load(JavaCompiler.class).iterator().next();

 

ServiceProvider是Java的util類之一,用於查找和加載部署在執行環境中的服務提供者。編程語言

找到JavaCompiler後,就能夠經過Java源代碼執行各類編譯診斷任務。爲了說明這個想法,讓咱們首先建立一個簡單的類,以下所示:ide

1 package com.mano.jcapidemo;
2 import java.util.Random;
3 public class MyClass {
4    public static void main(String[] args){
5       Random r = new Random();
6       System.out.println("Today your Lucky Number is:
7          "+r.nextInt(10));
8    }
9 }

 

如今,在建立Java源文件以後,咱們可使用名爲DiagnosticCollector的診斷收集器類將診斷收集在列表中。函數

建立另外一個類,從該類中咱們將調用編譯器來編譯上述類MyClass,並將診斷信息報告給該類。換句話說,咱們將建立一個應用程序來加載Java源文件,並由Java編譯器對其進行編譯,而且,若是源代碼中有任何錯誤,請確保將其報告給主機應用程序。工具

 1 package com.mano.jcapidemo;
 2  
 3 import com.mano.annotation.CustomAnnotation;
 4 import java.util.Set;
 5 import javax.annotation.processing.AbstractProcessor;
 6 import javax.annotation.processing.RoundEnvironment;
 7 import javax.annotation.processing.SupportedAnnotationTypes;
 8 import javax.annotation.processing.SupportedSourceVersion;
 9 import javax.lang.model.SourceVersion;
10 import javax.lang.model.element.Element;
11 import javax.lang.model.element.ElementKind;
12 import javax.lang.model.element.TypeElement;
13 import javax.tools.Diagnostic;
14 @SupportedAnnotationTypes("com.mano.annotation.CustomAnnotation")
15 @SupportedSourceVersion(SourceVersion.RELEASE_10)
16 public class CustomAnnotationProcessor extends
17       AbstractProcessor {
18    public CustomAnnotationProcessor() {
19    }   public Boolean process(Set<? extends
20           TypeElement> annotations,
21           RoundEnvironment roundEnv) {
22       for (Element e : roundEnv.getElementsAnnotatedWith
23             (CustomAnnotation.class)) {
24          if (e.getKind() != ElementKind.FIELD) {
25             processingEnv.getMessager().printMessage(
26                Diagnostic.Kind.WARNING,
27                "Not a field", e);
28             continue;
29          }
30       }
31       return true;
32    }
33 }

 

 

編譯器依賴於兩種服務:診斷偵聽器和文件管理器。若是提供了偵聽器,則將診斷信息提供給偵聽器;不然,將向偵聽器提供診斷信息。不然,診斷將以未指定的格式格式化,並定向到默認的錯誤輸出系統(System.err)。默認狀況下,編譯器工具與標準文件管理器關聯,而且能夠與知足其要求的任何其餘文件管理器一塊兒正常工做。學習

註釋處理器

編譯過程還包括註釋處理器。它執行編譯由註釋驅動的代碼的附加過程。處理過程按一系列輪次進行,其中每一個輪次處理其上一輪產生的註釋子集。實現註釋過程的接口是javax.annotation.processin.Processor。實現類必須提供一個無參數的構造函數,以供工具實例化處理器。處理基礎結構應遵循某些協議,例如:

  • 經過使用處理器類的無參數構造函數實例化註釋處理器。
  • 工具經過傳遞適當的ProcessingEnvironmentinstance實例來調用init方法。
  • 這些工具調用由Processor接口定義的方法,例如getSupportedAnnotationTypes()getSupportedOptions(), 和getSupportedSourceVersion()。這些方法在每次運行中調用一次,而不是在每一個回合中調用一次。
  • 最後,調用Processor對象上的process ()方法。

例如,簡單的註釋能夠定義以下:

1 package com.mano.jcapidemo;
2 import java.lang.annotation.ElementType;
3 import java.lang.annotation.Target;
4 @Target(ElementType.FIELD)
5 public@interface CustomAnnotation {
6 }

 

一個很是簡單的註釋處理器,用於警告將註釋應用於字段之外的任何其餘元素,以下所示:

 1 package com.mano.jcapidemo;
 2  
 3 import com.mano.annotation.CustomAnnotation;
 4 import java.util.Set;
 5 import javax.annotation.processing.AbstractProcessor;
 6 import javax.annotation.processing.RoundEnvironment;
 7 import javax.annotation.processing.SupportedAnnotationTypes;
 8 import javax.annotation.processing.SupportedSourceVersion;
 9 import javax.lang.model.SourceVersion;
10 import javax.lang.model.element.Element;
11 import javax.lang.model.element.ElementKind;
12 import javax.lang.model.element.TypeElement;
13 import javax.tools.Diagnostic;
14 @SupportedAnnotationTypes("com.mano.annotation.CustomAnnotation")
15 @SupportedSourceVersion(SourceVersion.RELEASE_10)
16 public class CustomAnnotationProcessor extends
17       AbstractProcessor {
18    public CustomAnnotationProcessor() {
19    }   public Boolean process(Set<? extends
20           TypeElement> annotations,
21           RoundEnvironment roundEnv) {
22       for (Element e : roundEnv.getElementsAnnotatedWith
23             (CustomAnnotation.class)) {
24          if (e.getKind() != ElementKind.FIELD) {
25             processingEnv.getMessager().printMessage(
26                Diagnostic.Kind.WARNING,
27                "Not a field", e);
28             continue;
29          }
30       }
31       return true;
32    }
33 }

 

SupportedAnnotationTypes定義註釋處理器將處理哪一種類型的註釋,SupportedSourceVersion定義其支持的版本。 咱們首先擴展AbstractProcessor抽象類,該類容許咱們覆蓋處理方法。 處理方法內部編寫的邏輯完成了全部技巧,這些技巧涉及咱們選擇設置哪些標準來處理註釋。 這最終決定了註釋的含義。

元素掃描儀

元素掃描器在編譯過程當中對全部語言元素執行分析。它根據訪問者模式構建,以根據源版本的發佈狀況,以默認行爲掃描程序元素。例如,ElementScanner9根據源版本RELEASE_9和RELEASE_10進行掃描,而ElementScanner8分別根據源版本RELEASE_8進行掃描。這兩個類均可以在javax.lang.model.utilpackage中找到。

編譯樹API Compiler Tree API

有時,有必要將整個Java源文件解析爲抽象語法樹,尤爲是爲了進行更深刻的分析。Java編譯器樹API遵照該要求,並與javax.lang.model包緊密關聯。它以與元素掃描器相同的模式構建,而且以相似的方式工做。密鑰類稱爲TreePathScanner。它訪問全部子樹節點,並有助於維護到父節點的路徑。要訪問特定節點,咱們能夠簡單地覆蓋相應的visitorXYZ方法。

總結

Java編譯器API從Java應用程序中提供對Java編譯器的編程訪問。顯而易見,此API有更深層的含義,在這裏咱們只涉及了其中的內容。可是,此快速介紹可能會提供有關在開始使用Java Compiler API時要查找的內容的線索。

參考

Java API文檔

相關文章
相關標籤/搜索