前言
最近在用Dagger開發(fā)應用,Dagger是google在square的基礎上去反射的依賴注入框架凌箕。
Dagger會根據(jù)定義的注解在編譯階段根據(jù)依賴注入的配置生成相應的代碼,來減少運行期間反射的開銷荠呐。
Dagger依賴了JavaPoet和JavaFormat來輔助實現(xiàn)生成代碼募疮,這里主要介紹下JavaPoet的內(nèi)容和使用。
JavaPoet
JavaPoet這樣定義自己的項目缆毁。
Use beautiful Java code to generate beautiful Java code
所以JavaPoet定義了一系列類來盡可能優(yōu)雅的描述java源文件的結(jié)構(gòu)。觀察JavaPoet的代碼主要的類可以分為以下幾種:
- Spec 用來描述Java中基本的元素到涂,包括類型脊框,注解,字段践啄,方法和參數(shù)等浇雹。
- AnnotationSpec
- FieldSpec
- MethodSpec
- ParameterSpec
- TypeSpec
- Name 用來描述類型的引用,包括Void屿讽,原始類型(int昭灵,long等)和Java類等。
- TypeName
- ArrayTypeName
- ClassName
- ParameterizedTypeName
- TypeVariableName
- WildcardTypeName
- CodeBlock 用來描述代碼塊的內(nèi)容伐谈,包括普通的賦值烂完,if判斷,循環(huán)判斷等诵棵。
- JavaFile 完整的Java文件抠蚣,JavaPoet的主要的入口。
- CodeWriter 讀取JavaFile并轉(zhuǎn)換成可閱讀可編譯的Java源文件履澳。
示例
下面通過一個例子來完整的實現(xiàn)一個Java類的定義嘶窄。
通過下面的maven依賴可以引用JavaPoet包怀跛。
<dependency>
<groupId>com.squareup</groupId>
<artifactId>javapoet</artifactId>
<version>1.7.0</version>
</dependency>
完整的代碼放在Github。這里介紹一下主要的方法柄冲。
- AnnotationSpec 添加MyAnnotation的注解吻谋,然后設置屬性hello=world。
private static AnnotationSpec makeAnnotationSpec() {
AnnotationSpec.Builder builder = AnnotationSpec.builder(ClassName.get("org.wcong.test.poet", "MyAnnotation"));
CodeBlock.Builder codeBlockBuilder = CodeBlock.builder().add("$S", "world");
builder.addMember("hello", codeBlockBuilder.build());
return builder.build();
}
- FieldSpec 創(chuàng)建hello的字段并初始化為“world”现横。
private static FieldSpec makeFieldSpec() {
FieldSpec.Builder fileSpecBuilder = FieldSpec.builder(String.class, "hello", Modifier.PRIVATE);
fileSpecBuilder.initializer(CodeBlock.of("\"world\""));
return fileSpecBuilder.build();
}
- MethodSpec 創(chuàng)建getHello,setHello,toString方法漓拾。
toString使用了ControlFlow判斷了hello不等于null,返回"hello world"戒祠,等于null的時候返回空晦攒。
private static MethodSpec makeToStringMethod() {
MethodSpec.Builder toStringBuilder = MethodSpec.methodBuilder("toString");
toStringBuilder.addModifiers(Modifier.PUBLIC);
toStringBuilder.returns(TypeName.get(String.class));
CodeBlock.Builder toStringCodeBuilder = CodeBlock.builder();
toStringCodeBuilder.beginControlFlow("if( hello != null )");
toStringCodeBuilder.add(CodeBlock.of("return \"hello \"+hello;\n"));
toStringCodeBuilder.nextControlFlow("else");
toStringCodeBuilder.add(CodeBlock.of("return \"\";\n"));
toStringCodeBuilder.endControlFlow();
toStringBuilder.addCode(toStringCodeBuilder.build());
return toStringBuilder.build();
}
private static MethodSpec makeSetMethod() {
MethodSpec.Builder setMethodSpecBuilder = MethodSpec.methodBuilder("setHello");
setMethodSpecBuilder.addModifiers(Modifier.PUBLIC);
setMethodSpecBuilder.returns(TypeName.VOID);
ParameterSpec.Builder parameterBuilder = ParameterSpec.builder(TypeName.get(String.class), "hello");
setMethodSpecBuilder.addParameter(parameterBuilder.build());
setMethodSpecBuilder.addCode(CodeBlock.builder().add("this.hello = hello;\n").build());
return setMethodSpecBuilder.build();
}
private static MethodSpec makeGetMethod() {
MethodSpec.Builder getMethodSpecBuilder = MethodSpec.methodBuilder("getHello");
getMethodSpecBuilder.addModifiers(Modifier.PUBLIC);
getMethodSpecBuilder.returns(TypeName.get(String.class));
getMethodSpecBuilder.addCode(CodeBlock.builder().add("return hello;\n").build());
return getMethodSpecBuilder.build();
}
- JavaFile JavaPoet的主入口,用來描述Java源文件得哆。
public static void main(String[] args) {
TypeSpec.Builder typeSpecBuilder = TypeSpec.classBuilder("JavaFile");
typeSpecBuilder.addAnnotation(makeAnnotationSpec());
typeSpecBuilder.addField(makeFieldSpec());
typeSpecBuilder.addMethods(makeMethodSpec());
JavaFile.Builder javaFileBuilder = JavaFile.builder("org.wcong.test.poet", typeSpecBuilder.build());
System.out.println(javaFileBuilder.build().toString());
}
運行后輸出下面的信息,就是一個完整的類文件了
package org.wcong.test.poet;
import java.lang.String;
@MyAnnotation(
hello = "world"
)
class JavaFile {
private String hello = "world";
public String getHello() {
return hello;
}
public void setHello(String hello) {
this.hello = hello;
}
public String toString() {
if( hello != null ) {
return "hello "+hello;
} else {
return "";
}
}
}
結(jié)語
dagger使用JavaPoet來保存自動生成的類的信息哟旗,并通過JavaFormat來格式化生成的Java源文件贩据。后面會介紹關(guān)于JavaFormat的內(nèi)容。