摘要:概述從開始提供了一個新的被稱為的工具,使用其提供的我們可以通過類似數(shù)據(jù)結(jié)構(gòu)的方式來訪問被編譯的的源代碼。例如我們定義了一個注解該注解接受一個的參數(shù),注意該注解僅可見于源代碼編譯過程。
概述
從JDK1.6開始提供了一個新的被稱為APT(Annotation Processing Tool)的工具,使用其提供的APT我們可以通過類似數(shù)據(jù)結(jié)構(gòu)的方式來訪問被編譯的Java的源代碼。
利用這個新的工具提供的API我們可以在編譯Java源代碼的同時對現(xiàn)有代碼進行增強和生成代碼,比之以往通過運行時的反射以及通過Java的動態(tài)代理或者運行時字節(jié)碼修改來增強要來的更簡單并且運行時的效率要更高(指啟動時間)
問題描述在Java程序運行時可以通過反射來獲取類的Meta信息,但是在APT中處理的是Java源代碼,此時無法直接獲取定義在Annotation里面的類型信息,因為沒有反射API可以使用。
例如我們定義了一個注解:
@Target(ElementType.TYPE) @Retention(RetentionPolicy.SOURCE) public @interface Service { Class[] value(); }
該注解接受一個Class的參數(shù),注意該注解僅可見于源代碼編譯過程。
如果想在APT中獲取Service.value,下面代碼是不可行的:
... Service service = ... Class[] cls = service.value(); ...
運行這段代碼會在編譯時拋出異常,因為在編譯時類型信息無法直接獲取,只有Native數(shù)據(jù)和String可以直接獲取。
解決方案如何解決該問題呢?我們需要使用APT提供的*Mirror API獲取Class的相關(guān)信息。
獲取AnnotationMirror對象首先獲取AnnotationMirror對象:
AnnotationMirror svcAnnoMirror = MoreElements.getAnnotationMirror(classElement, Service.class).get();
MoreElements是Google Auto庫里面的一個工具類,getAnnotationMirror方法比較簡單,它返回Service Annotation對應(yīng)的AnnotationMirror對象。
上面的classElement是一個javax.lang.model.element.Element實例,在這里它代表了申明了Service這個Annotation的類的元素。
獲取Annotation定義的元素列表在APT里面,Java源代碼會被解釋稱類似XML的結(jié)構(gòu),比如類,字段,方法,方法的參數(shù)等都會被解釋稱一個元素,每個元素都是Element的實例
然后獲取該Annotation里面定義的所有元素的列表:
SetelementSet = svcAnnoMirror.getElementValues().entrySet();
過濾出key是value的那個元素
if (entry.getKey().getSimpleName().toString().equals("value")) { AnnotationValues annoValue = entry.getValue(); }獲取TypeElement
有了AnnotationValue,我們就可以取得內(nèi)部的值:
Listvalues = (List ) annoValue.getValue();
因為我們定義了Service.value是一個Class數(shù)組,所以這里我們需要把返回值強制轉(zhuǎn)換成List。
為了獲取Service.value里面定義的Class信息,我們需要使用TypeMirror API
DeclaredType declaredType = (DeclaredType) value.getValue(); TypeElement typeElement = (TypeElement) declaredType.asElement();
有了TypeElement,我們就可以訪問該類型相關(guān)的信息了,比如獲取其完整類名:
typeElement.getQualifiedName().toString();
當(dāng)然獲取它的實現(xiàn)的接口或者定義在它內(nèi)部的方法或者字段都是可以的。
完整代碼AnnotationMirror svcAnnoMirror = MoreElements.getAnnotationMirror(classElement, Service.class).get(); Listtypes = new ArrayList<>(); Observable.from(svcAnnoMirror.getElementValues().entrySet()) .filter(entry -> "value".equals(entry.getKey().getSimpleName().toString())) .map(Map.Entry::getValue) .flatMap(annoValue -> Observable.from((List ) annoValue.getValue())) .map(annoValue -> (DeclaredType) annoValue.getValue()) .map(declaredType -> (TypeElement) declaredType.asElement()) .map(typeElem -> typeElem.getQualifiedName().toString()) .subscribe(types::add, logger::error);
上面代碼使用rxJava以及Lambda表達(dá)式來簡化代碼。
參見我的項目源碼:這里
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://specialneedsforspecialkids.com/yun/65799.html
摘要:關(guān)于后稱的操作我們知道其實就是文件,所以這里的操作有獲取移動刪除。操作啟動停止重啟綁定解綁獲取系統(tǒng)服務(wù)以及多用戶操作。權(quán)限操作檢查本是否有某種權(quán)限檢查某是否有某種權(quán)限檢查權(quán)限授予權(quán)限等等。 先放一張圖吧 showImg(https://segmentfault.com/img/remote/1460000015839908); 2.用處 1.Context的實現(xiàn)類有很多,但是Cont...
摘要:之所以在本地構(gòu)建,而沒有使用倉庫的,是因為,我們的鏡像采用了國內(nèi)阿里云的源,再加上某些很奇妙的網(wǎng)絡(luò)因素,在中自動構(gòu)建時,升級總會失敗。然而,在本地再次構(gòu)建成功。 見字如晤。 前段時間,Node.js 官方發(fā)布了Node 8.9.3 LTS版本,并且官網(wǎng)首頁提示新版本有重要安全更新,Important security releases, please update now! ,然后我立...
摘要:使用實現(xiàn)功能運行期注解案例使用簡單的注解,便可以設(shè)置布局,等效于使用實現(xiàn)路由綜合型案例比較全面的介紹從零起步,一步一步封裝簡易的路由開源庫。申明注解用的就是。返回值表示這個注解里可以存放什么類型值。 YCApt關(guān)于apt方案實踐與總結(jié) 目錄介紹 00.注解系列博客匯總 01.什么是apt 02.annotationProcessor和apt區(qū)別 03.項目目錄結(jié)構(gòu) 04.該案例作用 ...
閱讀 2847·2021-09-27 13:35
閱讀 624·2021-09-23 11:22
閱讀 2892·2019-08-30 15:54
閱讀 1612·2019-08-29 16:27
閱讀 2468·2019-08-29 15:05
閱讀 2350·2019-08-23 18:11
閱讀 3523·2019-08-23 16:32
閱讀 2941·2019-08-23 14:56