Android編譯時代碼生成之二(javapoet)

博客搬遷到這里 http://blog.fdawei.club,歡迎訪問,大家一起學習交流。

前面通過一篇博客介紹了注解和Apt,今天介紹一個有意思的開源庫javapoet。

poet意思是詩人,很形象的名稱,沒錯,就像詩人能寫出優美的詩句一樣,它能夠優雅的自動生成java代碼。下面就來一步一步解開它神秘的面紗。

javapoet用法

按照慣例,我們先使用它寫一個輸出Hello World的類??蠢?/p>

FieldSpec fieldSpec = FieldSpec.builder(String.class, "helloWorld", Modifier.PRIVATE)
        .initializer("\"Hello World!\"").build();

MethodSpec methodSpec = MethodSpec.methodBuilder("printHelloWorld")
        .addModifiers(Modifier.PUBLIC)
        .addCode("System.out.println(helloWorld)")
        .build();

TypeSpec classSpec = TypeSpec.classBuilder("HelloWorld")
.addModifiers(Modifier.PUBLIC)
        .addField(fieldSpec)
        .addMethod(methodSpec)     
        .build();

JavaFile javaFile = JavaFile.builder("me.fdawei", classSpec).build();

System.out.print(javaFile.toString());

運行結果


image

可以看見,確實已經幫我們生成了需要的類。下面詳細看看實現過程。

常用類

先介紹幾個常用類??疵挚赡艽蠹揖鸵呀浤軌虿碌剿麄兪鞘裁戳?。

  • FieldSpec 代表一個成員變量,一個字段聲明。
  • MethodSpec 代表一個構造函數或方法聲明。
  • TypeSpec 代表一個類,接口,或者枚舉聲明。
  • ParameterSpec 用來創建參數。
  • JavaFile包含一個頂級類的Java文件。
  • AnnotationSpec 用來創建注解。
  • TypeName 類型名,如在添加返回值類型是使用 TypeName.VOID
  • ClassName 用來包裝一個類,提供類名。

添加修飾關鍵字

Modifier是用來設置一些修飾關鍵字的,如,public、final、static等等,看其取值就一目了然。FieldSpec、MethodSpec、TypeSpec中都可以使用。

生成成員變量

FieldSpec fieldSpec = FieldSpec.builder(String.class, "helloWorld", Modifier.PRIVATE)
        .initializer("\"Hello World!\"").build();

使用initializer方法,可以在定義成員變量時對其添加初始化代碼。這里添加了一個String類型的成員變量helloWorld,并將它初始化為字符串 “Hellow World!”。

生成成員方法

MethodSpec methodSpec = MethodSpec.methodBuilder("printHelloWorld")
        .addModifiers(Modifier.PUBLIC)
        .addCode("System.out.println(helloWorld)")
        .build();

生成Public類型的方法printHelloWorld,實現輸出helloWorld變量的值。

addCode方法的使用比較簡單。javapoet中,除了使用addCode以字符串拼湊的方式添加代碼執行邏輯,javapoet還提供了更加優雅的方式。

MethodSpec methodSpec = MethodSpec.methodBuilder("printHelloWorld")
        .addModifiers(Modifier.PUBLIC)
        .addStatement("System.out.println(helloWorld)")
        .build();

addStatement添加一行執行代碼,并自動在末尾添加“;”和換行。如果是for、while、if這樣的控制結構,可以使用beginControlFlow和endControlFlow來實現

MethodSpec methodSpec = MethodSpec.methodBuilder("printHelloWorld")
        .addModifiers(Modifier.PUBLIC)
        .beginControlFlow("for(int i = 0; i < 5; i++)")
        .addStatement("System.out.println(helloWorld)")
        .endControlFlow()
        .build();

很明顯,這里使用for循環輸出五次"Hello World!"。

生成類

TypeSpec classSpec = TypeSpec.classBuilder("HelloWorld")
.addModifiers(Modifier.PUBLIC)
        .addField(fieldSpec)
        .addMethod(methodSpec)     
        .build();

生成名為 HelloWorld 的類,并添加了一個成員變量和一個方法。

TypeSpec創建類時,如果需要生成實現了接口或繼承其他類的類怎么辦?TypeSpec提供addSuperinterface方法和superclass方法供使用。

生成Java源文件

JavaFile javaFile =
        JavaFile.builder("me.fdawei", classSpec).build();

builder方法的第一個參數制定了源文件的包名,第二個參數就是需要生成的類的信息。

占位符

使用FieldSpec生成成員變量時,可以通過initializer方法為其設置初始化代碼,例子中就使用字符串“Hello World!”來初始化String類型的成員變量helloWorld。這樣問題就來了,如果使用字符串拼接的話,字符串中需要包含引號,這樣就非常難處理了,需要進行轉義。就是這樣的寫法

FieldSpec fieldSpec = FieldSpec.builder(String.class, "helloWorld", Modifier.PRIVATE)
        .initializer("\"Hello World!\"").build();

這樣話顯得很麻煩,如果字符串復雜的話,很容易出錯。這就要用到占位符了。這里可以使用$S來進行占位。

FieldSpec fieldSpec = FieldSpec.builder(String.class, "helloWorld", Modifier.PRIVATE)
        .initializer("$S", "Hello World!").build();

$S用來給一個字符串占位。除了$S之外,javapoet中還有三個占位符,分別是:

  • $L 用來給一個數字占位
  • $T 用來給一個類,接口,或者枚舉占位
  • $N 用來給我們自己生成的方法名或者變量名等占位

有了占位符,生成成員方法時我們也可以這樣寫

MethodSpec methodSpec = MethodSpec.methodBuilder("printHelloWorld")
        .addModifiers(Modifier.PUBLIC)
        .addCode("$T.out.println(helloWorld);\n", System.class)
        .build();

比較運行結果

image

看到不同了沒有,對,就是多了import java.lang.System。說明單純的字符串,javapoet只會原樣添加到代碼中,使用了占位符$T,則會被視為一種類型,會自動導入對應的包。

如果你想靜態導入,當然也是可以的,使用addStaticImport方法即可。

JavaFile javaFile = JavaFile.builder("me.fdawei", classSpec)
        .addStaticImport(Modifier.class, "*").build();
image

除了最基本的這些方法來組裝代碼外,javapoet還提供很多其他的添加不同元素的方法

  • TypeSpec.enumBuilder() 生成枚舉類型
  • TypeSpec.interfaceBuilder() 生成接口
  • MethodSpec.addJavadoc() 給方法添加注釋
  • MethodSpec.constructorBuilder() 創建構造方法
  • MethodSpec.addAnnotation() 添加注解

其實javapoet可以做的還不止這些,在以后的使用中可以慢慢發掘。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 229,836評論 6 540
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,275評論 3 428
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事?!?“怎么了?”我有些...
    開封第一講書人閱讀 177,904評論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,633評論 1 317
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,368評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,736評論 1 328
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,740評論 3 446
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,919評論 0 289
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,481評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,235評論 3 358
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,427評論 1 374
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,968評論 5 363
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,656評論 3 348
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,055評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,348評論 1 294
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,160評論 3 398
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,380評論 2 379

推薦閱讀更多精彩內容

  • Spring Cloud為開發人員提供了快速構建分布式系統中一些常見模式的工具(例如配置管理,服務發現,斷路器,智...
    卡卡羅2017閱讀 134,818評論 18 139
  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 172,711評論 25 708
  • 就算前路一個人再漫長再不可測都沒關系 怕的是沒那勇氣 有些事 硬著頭皮也就過了 無論有多少風雨 要知道還有許多和你...
    未簽收閱讀 159評論 0 0
  • 今天女兒上小學一年級報名,按學校要求進行一場入學測試考試。在孩子們考試的時間,等在教室外的家長們聊起來。有些...
    朣昽閱讀 648評論 2 3
  • 隨著越來越長大,接觸的人越來越多,聽到女生反對男生抽煙的聲音就越來越大,大部分的理由是好臭、不健康,但是我對...
    箜蒔閱讀 493評論 0 0