前言
對于我來說,javapoet也是不經意間發現的,日常android開發中:
主要使用mvp+rxjava+dagger2這套框架
在這套框架里每次寫 activity 或者 fragment 就會寫一套mvp+compent+module,如下圖:
生成內容.jpeg
經過長時間的重復編寫,發現這一套mvp+compent+module文件,只有名稱是變化的,所以只需要將名稱抽象出來,其他只需模板化,就能生成出上述java文件.
正當想怎么能夠快捷生成java文件,這時javapoet便出現,而且javapoet能夠完全滿足需求。
本文主要以javapoet的使用方法介紹為主,會將javapoet的基本api都介紹一遍,你也可以理解成javapoet的中文簡易教程
javapoet的基本介紹
(1)javapoet是一款可以自動生成java文件的第三方依賴
(2)簡潔易懂的api,上手快
(3)讓繁雜、重復的java文件,自動化生成,提高工作效率,簡化流程
javapoet的小試牛刀
為了展示javapoet的能力,這里以自動生成一個全新的mainactivity為例。
1
2
3
4
5
6
7
8
|
public class mainactivity extends activity{ @override protected void oncreate( @nullable bundle savedinstancestate) { super .oncreate(savedinstancestate); setcontentview(r.layout.activity_main); } } |
我在使用javapoet的時候,習慣從外向內逐一生成,但是這不是標準,這里可以按照自己的方式來理解和生成.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
|
public static void main(string[] args) { classname activity = classname.get( "android.app" , "activity" ); typespec.builder mainactivitybuilder = typespec.classbuilder( "mainactivity" ) .addmodifiers(modifier. public ) .superclass(activity); classname override = classname.get( "java.lang" , "override" ); classname bundle = classname.get( "android.os" , "bundle" ); classname nullable = classname.get( "android.support.annotation" , "nullable" ); parameterspec savedinstancestate = parameterspec.builder(bundle, "savedinstancestate" ) .addannotation(nullable) .build(); methodspec oncreate = methodspec.methodbuilder( "oncreate" ) .addannotation(override) .addmodifiers(modifier. protected ) .addparameter(savedinstancestate) .addstatement( "super.oncreate(savedinstancestate)" ) .addstatement( "setcontentview(r.layout.activity_main)" ) .build(); typespec mainactivity = mainactivitybuilder.addmethod(oncreate) .build(); javafile file = javafile.builder( "com.test" , mainactivity).build(); try { file.writeto(system.out); } catch (ioexception e) { e.printstacktrace(); } } |
通過在main方法中運行以上的代碼,就可以直接生成出mainactivity對象,自上而下的觀察上述代碼,你會發現javapoet讓java文件變得有邏輯性。
javapoet的常用類
- typespec————用于生成類、接口、枚舉對象的類
- methodspec————用于生成方法對象的類
- parameterspec————用于生成參數對象的類
- annotationspec————用于生成注解對象的類
- fieldspec————用于配置生成成員變量的類
- classname————通過包名和類名生成的對象,在javapoet中相當于為其指定class
- parameterizedtypename————通過mainclass和includeclass生成包含泛型的class
- javafile————控制生成的java文件的輸出的類
javapoet的常用方法
設置修飾關鍵字
1
|
addmodifiers(modifier... modifiers) |
modifier是一個枚舉對象,枚舉值為修飾關鍵字public、protected、private、static、final等等。
所有在javapoet創建的對象都必須設置修飾符(包括方法、類、接口、枚舉、參數、變量)。
設置注解對象
1
2
3
|
addannotation(annotationspec annotationspec) addannotation(classname annotation) addannotation( class <?> annotation) |
該方法即為類或方法或參數設置注解,參數即可以是annotationspec,也可以是classname,還可以直接傳遞class對象。
一般情況下,包含復雜屬性的注解一般用annotationspec,如果單純添加基本注解,無其他附加屬性可以直接使用classname或者class即可。
設置注釋
1
2
|
addjavadoc(codeblock block) addjavadoc(string format, object... args) |
在編寫類、方法、成員變量時,可以通過addjavadoc來設置注釋,可以直接傳入string對象,或者傳入codeblock(代碼塊)。
javapoet生成類、接口、枚舉對象
在javapoet中生成類、接口、枚舉,必須得通過typespec生成,而classbuilder、interfacebuilder、enumbuilder便是創建其關鍵的方法:
1
2
3
4
5
6
7
8
9
10
11
|
創建類: typespec.classbuilder("類名“) typespec.classbuilder(classname classname) 創建接口: typespec.interfacebuilder( "接口名稱" ) typespec.interfacebuilder(classname classname) 創建枚舉: typespec.enumbuilder( "枚舉名稱" ) typespec.enumbuilder(classname classname) |
繼承、實現接口
1
2
3
4
5
|
繼承類: .superclass(classname classname) 實現接口 .addsuperinterface(classname classname) |
繼承存在泛型的父類
當繼承父類存在泛型時,需要使用parameterizedtypename
1
|
parameterizedtypename get(classname rawtype, typename... typearguments) |
返回的parameterizedtypename對象,已經被添加泛型信息
方法
1
|
addmethod(methodspec methodspec) |
通過配置methodspec對象,使用addmethod方法將其添加進typespec中。
枚舉
1
|
addenumconstan(string enumvalue) |
通過addenumconstan方法添加枚舉值,參數為枚舉值名稱。
javapoet生成成員變量
javapoet生成成員變量是通過fieldspec的build方法生成.
1
|
builder(typename type, string name, modifier... modifiers) |
只要傳入typename(class)、name(名稱)、modifier(修飾符),就可以生成一個基本的成員變量。
成員變量一般來說由注解(annotation)、修飾符(modifier)、javadoc(注釋)、initializer(實例化)。
注解
1
|
addannotation(typename name) |
修飾符
1
|
addmodifiers(modifier ...modifier) |
注釋
1
|
addjavadoc(string format, object... args) |
由于上述三個方法,都在通用方法介紹過這里就不再重復介紹。
實例化
1
|
initializer(string format, object... args) |
即成員變量的實例化,例:
1
|
public activity mactivity = new activity; |
而 initializer方法中的內容就是“=”后面的內容 ,下面看下具體的代碼實現,上面的成員變量:
1
2
3
4
5
|
classname activity = classname.get( "android.app" , "activity" ); fieldspec spec = fieldspec.builder(activity, "mactivity" ) .addmodifiers(modifier. public ) .initializer( "new $t" , activity) .build(); |
javapoet生成方法
javapoet生成方法分為兩種,第一種是構造方法,另一種為常規的方法。
構造方法
1
|
methodspec.constructorbuilder() |
常規方法
1
|
methodspec.methodbuilder(string name) |
方法的主要構成有方法參數、注解、返回值、方法體、拋出異常五種,注解可以參考通用方法addannotation,其他方法我們將會一一介紹:
方法參數
1
|
addparameter(parameterspec parameterspec) |
設置方法參數的方法通過addparameterspec來實現,parameterspec的具體使用參考下一小節。
返回值
1
|
returns(typename returntype) |
設置方法的返回值,只需傳入一個typename對象,而typename是classname,parameterizedtypename的基類。
方法體
在javapoet中,設置方法體內容有兩個方法,分別是addcode和addstatement:
1
2
|
addcode() addstatement() |
這兩個本質上都是設置方法體內容,但是不同的是使用addstatement()方法時,你只需要專注于該段代碼的內容,至于結尾的分號和換行它都會幫你做好。
而addcode()添加的方法體內容就是一段無格式的代碼片,需要開發者自己添加其格式。
方法體模板
在javapoet中,設置方法體使用模板是比較常見的,因為addcode和addstatement方法都存在這樣的一個重載:
1
2
3
|
addcode(string format, object... args) addstatement(string format, object... args) |
在javapoet中,format中存在三種特定的占位符:
$t
$t 在javapoet代指的是typename,該模板主要將class抽象出來,用傳入的typename指向的class來代替。
1
2
|
classname bundle = classname.get( "android.os" , "bundle" ); addstatement( "$t bundle = new $t()" ,bundle) |
上述添加的代碼內容為:
1
|
bundle bundle = new bundle(); |
$n
$n在javapoet中代指的是一個名稱,例如調用的方法名稱,變量名稱,這一類存在意思的名稱
1
|
addstatement( "data.$n()" ,tostring) |
上述代碼添加的內容:
1
|
data.tostring(); |
$s
$s在javapoet中就和string.format中%s一樣,字符串的模板,將指定的字符串替換到$s的地方
1
|
.addstatement( "super.$s(savedinstancestate)" , "oncreate" ) |
即將"oncreate"字符串代替到$s的位置上.
拋出異常
1
|
.addexception(typename name) |
設置方法拋出異常,可以使用addexception方法,傳入指定的異常的classname,即可為該方法設置其拋出該異常.
javapoet生成方法參數
javapoet生成有參方法時,需要填充參數,而生成參數則需要通過parameterspec這個類。
1
|
addparameter(parameterspec parameterspec) |
初始化parameterspec
1
|
parameterspec.builder(typename type, string name, modifier... modifiers) |
給參數設置其class,以及參數名稱,和修飾符.
通常來說參數的構成包括:參數的類型(class)、參數的名稱(name)、修飾符(modifiers)、注解(annotation)
除了builder方法初始化類型、以及名稱、修飾符之外,其余可以通過如下方法進行設置:
添加修飾符
1
|
.addmodifiers(modifier modifier) |
添加注解
1
|
addannotation(typename name) |
添加修飾符、注解具體使用可參考通用方法。
javapoet生成注解
在javapoet創建類、成員變量、方法參數、方法,都會用到注解。
如果使用不包含屬性的注解可以直接通過
1
|
.addannotation(typename name) |
直接傳入typename或者class進行設置。
如果使用的注解包含屬性,并且不止一個時,這時候就需要生成annotationspec來解決,下面簡單了解下annotationspec。
初始化annotationspec
1
|
annotationspec.builder(classname type) |
可以發現初始化,只需傳入classname或者class即可。
設置屬性
1
|
addmember(string name, string format, object... args) |
使用addmember可以設置注解的屬性值,name對應的就是屬性名稱,format的內容即屬性體,同樣方法體的格式化在這里也是適用的。
javapoet如何生成代碼
如果上述內容你已經看完,那么恭喜你,你已經明白javapoet的意圖,但是現在的你,還差最后一步,即如何生成代碼。
javapoet中負責生成的類是javafile
1
|
javafile.builder(string packagename, typespec typespec) |
javafile通過向build方法傳入packagename(java文件的包名)、typespec(生成的內容)生成。
打印結果
1
|
javafile.writeto(system.out) |
生成的內容會輸出到控制臺中
生成文件
1
|
javafile.writeto(file file) |
生成的內容會以java文件的方式,存放到你傳入file文件的位置
結束語
當你讀完了本文,如果你產生下面的想法:
- javapoet原來還可以這樣
- javapoet編寫過程為什么那么流暢,原來java文件也可以用編程的方式生成
- javapoet可不可以改進我的編碼流程,提升效率
那么說明你已經對javapoet感興趣了,可以自己動手嘗試一下,感受下javapoet的魅力。
最后貼一張,javapoet秘籍,有了它會很好的幫助你使用javapoet.
以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持服務器之家。
原文鏈接:https://www.jianshu.com/p/3b3bd53ee36a