JavaPoet的使用指南
前言
對於我來說,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為例。
public class MainActivity extends Activity{ @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); } }
我在使用JavaPoet的時候,習慣從外向內逐一生成,但是這不是標準,這裡可以按照自己的方式來理解和生成.
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(); } }
[圖片上傳失敗...(image-fda864-1539928732296)]
通過在Main方法中執行以上的程式碼,就可以直接生成出MainActivity物件,自上而下的觀察上述程式碼,你會發現JavaPoet讓java檔案變得有邏輯性。
JavaPoet的常用類
- TypeSpec————用於生成類、介面、列舉物件的類
- MethodSpec————用於生成方法物件的類
- ParameterSpec————用於生成引數物件的類
- AnnotationSpec————用於生成註解物件的類
- FieldSpec————用於配置生成成員變數的類
- ClassName————通過包名和類名生成的物件,在JavaPoet中相當於為其指定Class
- ParameterizedTypeName————通過MainClass和IncludeClass生成包含泛型的Class
- JavaFile————控制生成的Java檔案的輸出的類
JavaPoet的常用方法
設定修飾關鍵字
addModifiers(Modifier... modifiers)
Modifier是一個列舉物件,列舉值為修飾關鍵字Public、Protected、Private、Static、Final等等。
所有在JavaPoet建立的物件都必須設定修飾符(包括方法、類、介面、列舉、引數、變數)。
設定註解物件
addAnnotation(AnnotationSpec annotationSpec) addAnnotation(ClassName annotation) addAnnotation(Class<?> annotation)
該方法即為類或方法或引數設定註解,引數即可以是AnnotationSpec,也可以是ClassName,還可以直接傳遞Class物件。
一般情況下,包含複雜屬性的註解一般用AnnotationSpec,如果單純新增基本註解,無其他附加屬性可以直接使用ClassName或者Class即可。
設定註釋
addJavadoc(CodeBlock block) addJavadoc(String format, Object... args)
在編寫類、方法、成員變數時,可以通過addJavadoc來設定註釋,可以直接傳入String物件,或者傳入CodeBlock(程式碼塊)。
JavaPoet生成類、介面、列舉物件
在JavaPoet中生成類、介面、列舉,必須得通過TypeSpec生成,而classBuilder、interfaceBuilder、enumBuilder便是建立其關鍵的方法:
建立類: TypeSpec.classBuilder("類名“) TypeSpec.classBuilder(ClassName className) 建立介面: TypeSpec.interfaceBuilder("介面名稱") TypeSpec.interfaceBuilder(ClassName className) 建立列舉: TypeSpec.enumBuilder("列舉名稱") TypeSpec.enumBuilder(ClassName className)
繼承、實現介面
繼承類: .superclass(ClassName className) 實現介面 .addSuperinterface(ClassName className)
繼承存在泛型的父類
當繼承父類存在泛型時,需要使用ParameterizedTypeName
ParameterizedTypeName get(ClassName rawType, TypeName... typeArguments)
返回的ParameterizedTypeName物件,已經被新增泛型資訊
方法
addMethod(MethodSpec methodSpec)
通過配置MethodSpec物件,使用addMethod方法將其新增進TypeSpec中。
列舉
addEnumConstan(String enumValue)
通過addEnumConstan方法新增列舉值,引數為列舉值名稱。
JavaPoet生成成員變數
JavaPoet生成成員變數是通過FieldSpec的build方法生成.
builder(TypeName type, String name, Modifier... modifiers)
只要傳入TypeName(Class)、name(名稱)、Modifier(修飾符),就可以生成一個基本的成員變數。
成員變數一般來說由註解(Annotation)、修飾符(Modifier)、Javadoc(註釋)、initializer(例項化)。
註解
addAnnotation(TypeName name)
修飾符
addModifiers(Modifier ...modifier)
註釋
addJavadoc(String format, Object... args)
由於上述三個方法,都在通用方法介紹過這裡就不再重複介紹。
例項化
initializer(String format, Object... args)
即成員變數的例項化,例:
public Activity mActivity = new Activity;
而 initializer方法中的內容就是“=”後面的內容 ,下面看下具體的程式碼實現,上面的成員變數:
ClassName activity = ClassName.get("android.app", "Activity"); FieldSpec spec = FieldSpec.builder(activity, "mActivity") .addModifiers(Modifier.PUBLIC) .initializer("new $T", activity) .build();
JavaPoet生成方法
JavaPoet生成方法分為兩種,第一種是構造方法,另一種為常規的方法。
構造方法
MethodSpec.constructorBuilder()
常規方法
MethodSpec.methodBuilder(String name)
方法的主要構成有方法引數、註解、返回值、方法體、丟擲異常五種,註解可以參考通用方法addAnnotation,其他方法我們將會一一介紹:
方法引數
addParameter(ParameterSpec parameterSpec)
設定方法引數的方法通過addParameterSpec來實現,ParameterSpec的具體使用參考下一小節。
返回值
returns(TypeName returnType)
設定方法的返回值,只需傳入一個TypeName物件,而TypeName是ClassName,ParameterizedTypeName的基類。
方法體
在JavaPoet中,設定方法體內容有兩個方法,分別是addCode和addStatement:
addCode() addStatement()
這兩個本質上都是設定方法體內容,但是不同的是使用addStatement()方法時,你只需要專注於該段程式碼的內容,至於結尾的分號和換行它都會幫你做好。
而addCode()新增的方法體內容就是一段無格式的程式碼片,需要開發者自己新增其格式。
方法體模板
在JavaPoet中,設定方法體使用模板是比較常見的,因為addCode和addStatement方法都存在這樣的一個過載:
addCode(String format, Object... args) addStatement(String format, Object... args)
在JavaPoet中,format中存在三種特定的佔位符:
$T
$T 在JavaPoet代指的是TypeName,該模板主要將Class抽象出來,用傳入的TypeName指向的Class來代替。
ClassName bundle = ClassName.get("android.os", "Bundle"); addStatement("$T bundle = new $T()",bundle)
上述新增的程式碼內容為:
Bundle bundle = new Bundle();
$N
$N在JavaPoet中代指的是一個名稱,例如呼叫的方法名稱,變數名稱,這一類存在意思的名稱
addStatement("data.$N()",toString)
上述程式碼新增的內容:
data.toString();
$S
$S在JavaPoet中就和String.format中%s一樣,字串的模板,將指定的字串替換到$S的地方
.addStatement("super.$S(savedInstanceState)","onCreate")
即將"onCreate"字串代替到$S的位置上.
丟擲異常
.addException(TypeName name)
設定方法丟擲異常,可以使用addException方法,傳入指定的異常的ClassName,即可為該方法設定其丟擲該異常.
JavaPoet生成方法引數
JavaPoet生成有參方法時,需要填充引數,而生成引數則需要通過ParameterSpec這個類。
addParameter(ParameterSpec parameterSpec)
初始化ParameterSpec
ParameterSpec.builder(TypeName type, String name, Modifier... modifiers)
給引數設定其Class,以及引數名稱,和修飾符.
通常來說引數的構成包括:引數的型別(Class)、引數的名稱(name)、修飾符(modifiers)、註解(Annotation)
除了builder方法初始化型別、以及名稱、修飾符之外,其餘可以通過如下方法進行設定:
新增修飾符
.addModifiers(Modifier modifier)
添加註解
addAnnotation(TypeName name)
新增修飾符、註解具體使用可參考通用方法。
JavaPoet生成註解
在JavaPoet建立類、成員變數、方法引數、方法,都會用到註解。
如果使用不包含屬性的註解可以直接通過
.addAnnotation(TypeName name)
直接傳入TypeName或者Class進行設定。
如果使用的註解包含屬性,並且不止一個時,這時候就需要生成AnnotationSpec來解決,下面簡單瞭解下AnnotationSpec。
初始化AnnotationSpec
AnnotationSpec.builder(ClassName type)
可以發現初始化,只需傳入ClassName或者Class即可。
設定屬性
addMember(String name, String format, Object... args)
使用addMember可以設定註解的屬性值,name對應的就是屬性名稱,format的內容即屬性體,同樣方法體的格式化在這裡也是適用的。
JavaPoet如何生成程式碼
如果上述內容你已經看完,那麼恭喜你,你已經明白JavaPoet的意圖,但是現在的你,還差最後一步,即如何生成程式碼。
JavaPoet中負責生成的類是JavaFile
JavaFile.builder(String packageName, TypeSpec typeSpec)
JavaFile通過向build方法傳入PackageName(Java檔案的包名)、TypeSpec(生成的內容)生成。
列印結果
javaFile.writeTo(System.out)
生成的內容會輸出到控制檯中
生成檔案
javaFile.writeTo(File file)
生成的內容會以java檔案的方式,存放到你傳入File檔案的位置
結束語
當你讀完了本文,如果你產生下面的想法:
- JavaPoet原來還可以這樣
- JavaPoet編寫過程為什麼那麼流暢,原來Java檔案也可以用程式設計的方式生成
- JavaPoet可不可以改進我的編碼流程,提升效率
那麼說明你已經對JavaPoet感興趣了,可以自己動手嘗試一下,感受下JavaPoet的魅力。
最後貼一張,JavaPoet祕籍,有了它會很好的幫助你使用JavaPoet.

JavaPoet使用圖譜.jpeg
(註明:該圖來自 ofollow,noindex">walfud的個人部落格 )