Annotation & Annotation process Tool

前面是一些名詞的解釋和說明存捺,例子創(chuàng)建可以直接看后面的“創(chuàng)建過程”的章節(jié)。

本文主要參考網上各個大神的總結和自己使用過程的問題完成的,如果你發(fā)現(xiàn)有你的文章的內容爷绘,請通知我,我將你的文章放在引用目錄里进倍,謝謝土至。
如有錯誤和需要勘正的地方,請指教猾昆。

Annotation

注解是JDK5.0引入的新特性
JDK5.0 當時提供了三個注解: @Deprecated(廢棄的陶因、過時的)、@Override(重寫毡庆、覆蓋)坑赡、@SuppressWarnings(壓縮警告)

  1. 注解相當于一種標記,在程序中加入注解就等于為程序打上某種標記么抗。
  2. javac編譯器毅否、開發(fā)工具和其他程序可以通過反射來了解類及各元素上的標記信息。
  3. 注解可以加在包蝇刀、類螟加、屬性、方法吞琐、方法的參數(shù)以及局部變量上捆探。

元注解(meta-annotaion)

JDK5.0引入,負責注解其他注解

元注解包含:

  1. @Target:規(guī)定自定義Annotation所修飾的對象范圍
    • ElementType.CONSTRUCTOR站粟,構造器聲明
    • ElementType.FIELD黍图,成員變量、對象奴烙、屬性(包括enum實例)
    • ElementType.LOCAL_VARIABLE助被,局部變量聲明
    • ElementType.METHOD,方法聲明
    • ElementType.PACKAGE切诀,包聲明
    • ElementType.PARAMETER揩环,參數(shù)聲明
    • ElementType.TYPE,類幅虑、接口(包括注解類型)或enum聲明
    • 同時支持多種范圍設定丰滑,e.g.:
      @Target({ElementType.TYPE,ElementType.FIELD})
  2. @Retention:對Annotation的“生命周期”限制,表示需要在什么級別保存該注釋信息
    • RetentionPolicy.SOURCE倒庵,在源文件中有效
    • RetentionPolicy.CLASS褒墨,在class文件中有效
    • RetentionPolicy.RUNTIME炫刷,在運行時有效
  3. @Documented:用于描述其他類型的annotation應該被作為被標注的程序成員的公共API,因此可以被例如javadoc此類工具文檔化貌亭,Documented是一個標記注解柬唯,沒有成員
  4. @Inherited:標記注解,被標注的類型是被繼承的圃庭,主要用于類锄奢。

自定義注解

使用@interface自定義注釋時,自動繼承了java.lang.annotation.Annotation接口剧腻,由編譯程序自動完成其他細節(jié)拘央。在定義注解時,不能繼承其他的注解或接口书在。@interface用來聲明一個注解灰伟,其中的每一個方法實際上是聲明了一個配置參數(shù)。方法的名稱就是參數(shù)的名稱儒旬,返回值類型就是參數(shù)類型(只能是基本類型栏账、Class、String栈源、enum)挡爵。可以通過default來聲明參數(shù)的默認值甚垦。

注解使用的參數(shù)

只能用基本類型byte,short,char,int,long,float,double,boolean八種基本數(shù)據類型和String,Enum,Class,Annotation等數(shù)據類型茶鹃,以及這些類型的數(shù)組。
必須有明確的值艰亮,可以在定義注解的默認值中指定闭翩;或者 使用注解時指定,非基本類型的注解元素的值不可為null迄埃。

自定義注解的局限

  1. 不能修改已有的源文件疗韵,可以創(chuàng)建新的源文件

APT(Used in Android Studio)

APT(Annotation Processing Tool)是一種處理注釋的工具,它對源碼文件進行檢測找出其中的Annotation侄非,使用Annotation進行額外的處理蕉汪。
Annotation處理器在處理Annotation時可以根據源文件中的Annotation生成額外的源文件和其他的文件(文件具體內容由Annotation處理器的編寫者決定),APT還會編譯生成的源文件和原來的源文件彩库,將它們一起生成class文件。

創(chuàng)建過程

  1. 創(chuàng)建一個Java Library(比如叫做annotation)先蒋,放置自定義的annotation和關聯(lián)代碼骇钦。

    @Target(ElementType.TYPE)
    @Retention(RetentionPolicy.CLASS)  
    public @interface Test {   }
    
  2. 配置該library的build.gradle

    該配置信息在android studio將自動生成

    apply plugin: 'java' 
    sourceCompatibility = 1.7  
    targetCompatibility = 1.7   
    dependencies { 
        compile fileTree(dir: 'libs', include: ['*.jar']) 
    }  
    
  3. 創(chuàng)建一個Java library(比如叫做compiler),放置自定義的Annotation Processor竞漾。

    AutoService是一個開源庫提供的注冊Processor的方法眯搭。

    @AutoService(Processor.class)
    public class TestProcessor extends AbstractProcessor {
        @Override
        public Set<String> getSupportedAnnotationTypes() {
            return Collections.singleton(Test.class.getCanonicalName());
        }
        @Override
        public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
            return false;
        }
    }
    
  4. 配置build.gradle

    apply plugin: 'java'
    sourceCompatibility = 1.7 
    targetCompatibility = 1.7 
    dependencies {
        compile fileTree(dir: 'libs', include: ['*.jar'])
        compile 'com.google.auto.service:auto-service:1.0-rc2'
        compile 'com.squareup:javapoet:1.7.0'
        compile project(':annotation')
    }
    
  5. 配置Project的build.gradle

    加在buildscript的dependencies中

    classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8'
    
  6. 配置app的build.gradle

    增加pluge

    apply plugin: 'com.neenbedankt.android-apt'
    

    dependencies中增加

    compile project(':annotation')
    apt project(':compiler')
    
  7. 新版本android studio 5和6的配置會報錯窥翩,只要直接使用annotationProcessor引入依賴就好,即源碼如下:

    dependencies中增加

    compile project(':annotation')
    annotationProcessor project(':compiler')
    

Debug自定義Annotaion Processor

編譯過程:

  1. javac啟動一個JVM運行processor鳞仙;
  2. compiler編譯代碼寇蚊,所以processor生成的代碼可以被編譯進apk;
  3. IDE啟動JVM運行代碼棍好。
  1. 將需要debug的processor加入compiler中

    • 在setting中打開Enable annotation processing(setting[需要在File->Other Settings->Default Setting 或者 Android studio歡迎頁面中的Configure->Preferences]->Build,Execution,Deployment->Compiler->Annotation Processors)
    • Processor FQ Name中增加一個自定義Processor的全路徑
  2. 設置javac為debug模式

    • 在Annotation Processors的設置項上面的Java Compiler中

    • 設置Additional command line parameters中設置:

      -J-Xdebug -J-Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=5005
      
  3. 增加一個遠程編譯選項并啟動編譯

    • 打開項目的Run/Debug Configurations
    • 在左邊欄中仗岸,點擊“+”增加一個Remote,確定借笙。
  4. 設置項目gradle.properties增加:

    org.gradle.jvmargs=-Xmx1536m -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=5005
    
  5. 點擊調試按鈕扒怖,打開遠程調試功能(這個時候自定義processor中的斷點顯示生效)

  6. 重新編譯工程,斷點響應

注1:1业稼、2步驟在實際中發(fā)現(xiàn)盗痒,不是必須要設置的,具體1低散、2步驟會有什么作用俯邓,還在研究。
注2:當遇到unable to open debugger port: connection refused的錯誤時熔号,是因為:

  1. 當前的端口號被占用稽鞭,你需要找到一個你電腦未被占用的端口號進行調試
  2. 工程引用的所有gradle.properties文件中,存在未加調試命令的文件

常用操作

  1. 獲取VariableElement的類型的TypeElement:Types.asElement(VariableElement.asType()):
    • 注意:如果類型是基本類型跨嘉,則返回值是null川慌,需要通過Types.boxedClass((PrimitiveType) VariableElement.asType());獲取到裝箱類的類型,基本類型只有PrimitiveType祠乃,他是一個TypeMirror梦重。
  2. TypeElement可以通過getEnclosingElement().toString()獲取包名,getSimpleName().toString()獲取類名
  3. 數(shù)組的處理:asType()亮瓷,返回ArrayType琴拧,getComponentType()返回是哪種類型的數(shù)組
  4. List的處理:asType(),返回DeclaredType嘱支,getTypeArguments()獲取是哪種類型的list蚓胸。

相關類說明

AbstractProcessor

  • init:ProcessingEnvironment,參數(shù)ProcessingEvnironment提供很多有用的工具類除师。
  • process:Set<TypeElement> RoundEnvironment沛膳,RoundEvnironment可以用來查詢出包含特定注解的被注解元素。
    1. 注意問題:
      • 可能你使用的源文件還未編譯汛聚,會拋出異常MirroredTypeException
      • 可能存在process多次調用锹安,因為處理之后有新的文件生成,所以需要注意內部數(shù)據的更新和清空問題。
  • getSupportedAnnotationTypes叹哭,指定這個注解處理器是注冊給哪個注解的忍宋。
  • getSupportedSourceVersion,指定你使用的Java版本风罩。

ProcessingEnvironment

  • getElementUtils:獲取element的操作類糠排,用于掃描源碼文件,源碼的每一個部分都是一個element超升,如圖:

    package com.example;    // PackageElement
    
    public class Foo {        // TypeElement
    
    private int a;      // VariableElement
    private Foo other;  // VariableElement
    
    public Foo () {}    // ExecuteableElement
    
    public void setA (  // ExecuteableElement
                     int newA   // TypeElement
                     ) {}
    }
    

    Element可以是類入宦、方法、變量等等廓俭。

  • getMessager: 獲取Messager的操作類云石,用于報告錯誤、警告 以及 提示信息的途徑研乒。

Test

  1. testCompile 'com.google.testing.compile:compile-testing:0.8':但是因為編譯出來的文件中存在當前工程沒有的類汹忠,所以雖然測試用例過了,但是依然會報錯雹熬。

使用缺點

  1. 額外生成一定量的類:編譯時間加長宽菜、包變大
  2. 可讀性比較差:對代碼的理解需要一定的門檻

引用文章

  1. annotation processing tool教程
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市竿报,隨后出現(xiàn)的幾起案子铅乡,更是在濱河造成了極大的恐慌,老刑警劉巖烈菌,帶你破解...
    沈念sama閱讀 221,695評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件阵幸,死亡現(xiàn)場離奇詭異,居然都是意外死亡芽世,警方通過查閱死者的電腦和手機挚赊,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,569評論 3 399
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來济瓢,“玉大人荠割,你說我怎么就攤上這事⊥” “怎么了蔑鹦?”我有些...
    開封第一講書人閱讀 168,130評論 0 360
  • 文/不壞的土叔 我叫張陵,是天一觀的道長箕宙。 經常有香客問我嚎朽,道長,這世上最難降的妖魔是什么柬帕? 我笑而不...
    開封第一講書人閱讀 59,648評論 1 297
  • 正文 為了忘掉前任哟忍,我火速辦了婚禮室囊,結果婚禮上,老公的妹妹穿的比我還像新娘魁索。我一直安慰自己,他們只是感情好盼铁,可當我...
    茶點故事閱讀 68,655評論 6 397
  • 文/花漫 我一把揭開白布粗蔚。 她就那樣靜靜地躺著,像睡著了一般饶火。 火紅的嫁衣襯著肌膚如雪鹏控。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,268評論 1 309
  • 那天肤寝,我揣著相機與錄音当辐,去河邊找鬼。 笑死鲤看,一個胖子當著我的面吹牛缘揪,可吹牛的內容都是我干的。 我是一名探鬼主播义桂,決...
    沈念sama閱讀 40,835評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼找筝,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了慷吊?” 一聲冷哼從身側響起袖裕,我...
    開封第一講書人閱讀 39,740評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎溉瓶,沒想到半個月后急鳄,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經...
    沈念sama閱讀 46,286評論 1 318
  • 正文 獨居荒郊野嶺守林人離奇死亡堰酿,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 38,375評論 3 340
  • 正文 我和宋清朗相戀三年疾宏,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片胞锰。...
    茶點故事閱讀 40,505評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡灾锯,死狀恐怖,靈堂內的尸體忽然破棺而出嗅榕,到底是詐尸還是另有隱情顺饮,我是刑警寧澤,帶...
    沈念sama閱讀 36,185評論 5 350
  • 正文 年R本政府宣布凌那,位于F島的核電站兼雄,受9級特大地震影響,放射性物質發(fā)生泄漏帽蝶。R本人自食惡果不足惜赦肋,卻給世界環(huán)境...
    茶點故事閱讀 41,873評論 3 333
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧佃乘,春花似錦囱井、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,357評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至程帕,卻和暖如春住练,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背愁拭。 一陣腳步聲響...
    開封第一講書人閱讀 33,466評論 1 272
  • 我被黑心中介騙來泰國打工讲逛, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人岭埠。 一個月前我還...
    沈念sama閱讀 48,921評論 3 376
  • 正文 我出身青樓盏混,卻偏偏與公主長得像,于是被迫代替她去往敵國和親惜论。 傳聞我的和親對象是個殘疾皇子括饶,可洞房花燭夜當晚...
    茶點故事閱讀 45,515評論 2 359

推薦閱讀更多精彩內容