簡介
編譯時注解以其在保有注解低耦合等傳統特點的同時又能兼顧性能被開發人員所熱愛,但是,在寫編譯過程動態生成代碼文件時的瑣碎工作讓人頭疼,square公司推出的javapoet則完美的解決了這一問題,讓動態生成代碼不在難寫。這里介紹下這個框架。
一、注解部分
這里不在對注解部分做詳細的描述,網上有很多關于java注解的資料,再此只對在做注解時運用到的兩個注解和一個抽象類進行大概的介紹。
寫注解時用到的兩個注解Retention和Target,其中Retention注解的屬性值為RetentionPolicy類型,而RetentionPolicy為枚舉類:
public enum RetentionPolicy { /** * Annotations are to be discarded by the compiler. */ SOURCE, /** * Annotations are to be recorded in the class file by the compiler * but need not be retained by the VM at run time. This is the default * behavior. */ CLASS, /** * Annotations are to be recorded in the class file by the compiler and * retained by the VM at run time, so they may be read reflectively. * * @see java.lang.reflect.AnnotatedElement */ RUNTIME} 其中的三個枚舉類型代表這注解的運行范圍 SOURCE:停留在代碼中,不會參與編譯;
ClASS:會被記錄在Class文件中,但不參與運行時調用;
RUNTIME:運行時可用。
Target注解的屬性值是ElementType,作用是規定被注解對象的具體類型
public enum ElementType { /** Class, interface (including annotation type), or enum declaration */ TYPE, /** Field declaration (includes enum constants) */ FIELD, /** Method declaration */ METHOD, /** Formal parameter declaration */ PARAMETER, /** Constructor declaration */ CONSTRUCTOR, /** Local variable declaration */ LOCAL_VARIABLE, /** Annotation type declaration */ ANNOTATION_TYPE, /** Package declaration */ PACKAGE, /** * Type parameter declaration * * @since 1.8 */ TYPE_PARAMETER, /** * Use of a type * * @since 1.8 */ TYPE_USE} 還有一個編譯時所需要的抽象類AbstractPRocessor,想要了解的更多可以看下鴻洋大神的博客http://blog.csdn.net/lmj623565791/article/details/43452969
二、Javapoet部分
進入重點,首先明白在一個.java文件的構造中,包含四大元素:成員變量(Field)、方法(method)、類或接口(Type)、文件(File)。在Javapoet中,對這四大元素有對應的操作類:
FieldSpec: 負責控制成員變量及常量的聲明 MethodSpec: 負責生成類中的方法 TypeSpec: 負責類或者接口的部分生成 JavaFile: 負責在根據制定的位置進行文件的輸出,以及進行必要的類包導入
先上一段經典的helloworld紀念逝去的青春:
FieldSpec fieldSpec = FieldSpec.builder(String.class,"world") .addModifiers(Modifier.PRIVATE,Modifier.STATIC,Modifier.FINAL) .initializer("$S","World") .build(); MethodSpec methodSpec = MethodSpec.methodBuilder("main") .addModifiers(Modifier.PUBLIC, Modifier.STATIC) .returns(void.class) .addParameter(String[].class, "args") .addStatement("$T.out.println($S+$N+/"$L/")", System.class,"Hello",fieldSpec,"!") .build(); TypeSpec typeSpec = TypeSpec.classBuilder("HelloWorld") .addModifiers(Modifier.PUBLIC) .addField(fieldSpec) .addMethod(methodSpec) .build(); JavaFile javaFile = JavaFile.builder("com.example",typeSpec) .build(); javaFile.writeTo(System.out); 生成代碼如下:
可以注意到,除了JavaFile中,都對Modifier進行了使用,這個類的作用就是設置聲明、方法、以及類的修飾語關鍵字,它本身是一個枚舉類。
addStatement方法可以直接寫入代碼行,需要注意的時不用加”;”
再細致點可以發現,輸出語句中使用了$S、$L、$N、$T四種占位符
$T:表示需要調用類或者接口;
$L:表示要對應的常量
$S:表示對應的字符串(和$L的區別在于,字符串進入代碼中仍為字符串,而$L則不會加"")
$N:表示對應(FieldSpec、MethodSpec、TypeSpec)要注入的變量常量、方法、類的名字。
需要注意的是,在Javapoet中會幫你自動引入包,如果想要手動引入自己需要的包,還可以通過JavaFile.Builder生成的對象調用addStaticImort( )方法。
在JavaPoet中還有更多好用的方法,比如beginControlFlow和endControlFlow等,在github上可以直接看到,就不在一一例舉了
github地址:https://github.com/square/javapoet
新聞熱點
疑難解答