介紹
JavaPoet是用於產生.Java源檔案的Java API。
當處理諸如注釋處理或與中繼資料檔案互動(例如,資料庫模式、協議格式)時,源檔案產生可能非常有用。通過產生代碼,您消除了編寫樣板檔案的需要,同時也保留了中繼資料的單一來源。
整合到項目中
<!-- https://mvnrepository.com/artifact/com.squareup/javapoet --> <dependency> <groupId>com.squareup</groupId> <artifactId>javapoet</artifactId> <version>1.11.0</version> </dependency>
代碼產生 類
//產生類 TypeSpec helloWorld=TypeSpec.classBuilder("HelloWorld") .build(); //Java檔案產生 JavaFile javaFile=JavaFile.builder("com.itcast.lyc",helloWorld).build(); try { //把檔案內容寫入到 視窗列印出來 javaFile.writeTo(System.out); } catch (IOException e) { e.printStackTrace(); }
產生內容如下:
package com.itcast.lyc;class HelloWorld {}
方法
普通的方法列子
//產生類構造器 TypeSpec.Builder helloWorldBuilder=TypeSpec.classBuilder("HelloWorld"); MethodSpec main=MethodSpec.methodBuilder("main")//方法的構造器 .addParameter(String[].class,"args")//添加參數 .returns(void.class)//添加傳回值 .addStatement("$T.out.println($S)",System.class,"helloWorld")//新增內容 .addStatement("$T.out.println($L)",System.class,100L)//顯示字元 .build(); TypeSpec helloWorld=helloWorldBuilder.addMethod(main).build(); //Java檔案產生 JavaFile javaFile=JavaFile.builder("com.itcast.lyc",helloWorld).build(); try { //把檔案內容寫入到 視窗列印出來 javaFile.writeTo(System.out); } catch (IOException e) { e.printStackTrace(); }
其中$T代表類的.class類,使用$T和adddStatement匹配能自動匯入包,$S表示注入字串,adddStatement的一種注入字串格式的文法,會自動幫語句添加分號和分行符號,另外還有$L表示數字類型。
產生代碼如下:
package com.itcast.lyc;import java.lang.String;import java.lang.System;class HelloWorld { void main(String[] args) { System.out.println("helloWorld"); System.out.println(100); }}
方法添加代碼的方式還有.addCode("asdasds;\n"),但是.addCode不會自動產生分號和換行,所以也不用,還可以這樣寫.addCode(CodeBlock.builder().addStatement("$S","|sdsad").build())。 控制流程 JavaPoet為產生控制流程,給我們提供了便利的API,比如,我們想產生如下內容:
if (true){ System.out.println("ok");}
我們很難想像如果讓我們自己列印{}括弧帶來的麻煩,所以JavaPoet在方法構造器中提供了beginControlFlow和endControlFlow。
MethodSpec main=MethodSpec.methodBuilder("main")//方法的構造器 .addParameter(String[].class,"args")//添加參數 .returns(void.class)//添加傳回值 .addStatement("$T.out.println($S)",System.class,"helloWorld")//新增內容 .addStatement("$T.out.println($L)",System.class,100L)//顯示字元 .beginControlFlow("if(true)")//控制流程開始 .addStatement("$T.out.println($S)",System.class,"ok") .endControlFlow()//控制流程結束 .build();
抽象類別
MethodSpec abstractMethon=MethodSpec.methodBuilder("testAbs") .addModifiers(Modifier.PUBLIC,Modifier.ABSTRACT) .build(); TypeSpec typeSpec=TypeSpec.classBuilder("TestAbs") .addModifiers(Modifier.PUBLIC,Modifier.ABSTRACT) .addMethod(abstractMethon) .build();
介面類
MethodSpec abstractMethon=MethodSpec.methodBuilder("testInterfaces") .addModifiers(Modifier.PUBLIC,Modifier.ABSTRACT) .build(); TypeSpec typeSpec=TypeSpec.interfaceBuilder("TestInterfaces") .addModifiers(Modifier.PUBLIC) .addField(FieldSpec.builder(String.class,"ONLY_ONCE") .addModifiers(Modifier.PUBLIC,Modifier.STATIC,Modifier.FINAL) .initializer("$S","OKKK") .build()) //添加欄位 .addMethod(abstractMethon) .build();
構造方法
//構造方法 MethodSpec consructorMethod=MethodSpec.constructorBuilder() .addModifiers(Modifier.PUBLIC) .addParameter(Integer.class,"age")//參數 .addStatement("this.$N=$N","age","age")//添加樣式代碼$N表示當前類的引用 .build(); TypeSpec helloWorld= helloWorldBuilder .addMethod(main)//添加main方法 .addField(FieldSpec.builder(Integer.class,"age").addModifiers(Modifier.PRIVATE).build())//添加欄位 .addMethod(consructorMethod)//添加構造方法 .build();
添加參數
.addParameter(Integer.class,"age")//參數
ParameterizedTypeName parameterizedTypeNameMap=ParameterizedTypeName.get( ClassName.get(Map.class), ClassName.get(Integer.class), ParameterizedTypeName.get( ClassName.get(Class.class), WildcardTypeName.subtypeOf(ClassName.get(Object.class)) ) ); ParameterizedTypeName parameterizedTypeNameList=ParameterizedTypeName.get( ClassName.get(List.class), WildcardTypeName.subtypeOf(ClassName.get(Integer.class)) ); //添加帶參數的方法 MethodSpec parmMethod=MethodSpec.methodBuilder("welomeBeiJing") .addParameter(String.class,"parm") .addParameter(ParameterSpec.builder(parameterizedTypeNameMap,"map").build()) .addParameter(ParameterSpec.builder(parameterizedTypeNameList,"list").build()) .build();最後產生效果:
void welomeBeiJing(String parm, Map<Integer, Class<?>> map, List<? extends Integer> list) { } 需要產生萬用字元的參數 使用
.addParameter(ParameterSpec.builder(TypeVariableName.get("T"),"t").build())下面引用別人的圖 加深理解: 點擊開啟連結
添加欄位
.addField(FieldSpec.builder(Integer.class,"age").addModifiers(Modifier.PRIVATE).build())//添加欄位
Enums
File file=new File(System.getProperty("user.dir"),"\\src\\main\\java"); TypeSpec typeSpec=TypeSpec.enumBuilder("EnumsTest") .addModifiers(Modifier.PUBLIC) .addEnumConstant("Rock",TypeSpec.anonymousClassBuilder("$S","Page") .addMethod(MethodSpec.methodBuilder("toString") .addAnnotation(Override.class) .addModifiers(Modifier.PUBLIC) .addStatement("return $S","avalanche") .returns(String.class) .build()) .build()) .addEnumConstant("Sci",TypeSpec.anonymousClassBuilder("$S","ssss").build()) .addEnumConstant("Apple",TypeSpec.anonymousClassBuilder("$S","sad").build()) .addField(String.class,"hand",Modifier.PRIVATE,Modifier.FINAL) .addMethod(MethodSpec.constructorBuilder() .addParameter(String.class,"hand") .addStatement("this.$N=$N","hand","hand").build()) .build(); JavaFile javaFile=JavaFile.builder("com.itcast.lyc.javapoet",typeSpec).build(); javaFile.writeTo(file); 產生代碼:
package com.itcast.lyc.javapoet;import java.lang.Override;import java.lang.String;public enum EnumsTest { Rock("Page") { @Override public String toString() { return "avalanche"; } }, Sci("ssss"), Apple("sad"); private final String hand; EnumsTest(String hand) { this.hand=hand; }}枚舉類型通過TypeSpec.enumBuilder構造器進行添加枚舉類。
內部類
TypeSpec comparator = TypeSpec.anonymousClassBuilder("") .addSuperinterface(ParameterizedTypeName.get(Comparator.class, String.class)) .addMethod(MethodSpec.methodBuilder("compare") .addAnnotation(Override.class) .addModifiers(Modifier.PUBLIC) .addParameter(String.class, "a") .addParameter(String.class, "b") .returns(int.class) .addStatement("return $N.length() - $N.length()", "a", "b") .build()) .build();TypeSpec helloWorld = TypeSpec.classBuilder("HelloWorld") .addMethod(MethodSpec.methodBuilder("sortByLength") .addParameter(ParameterizedTypeName.get(List.class, String.class), "strings") .addStatement("$T.sort($N, $L)", Collections.class, "strings", comparator) .build()) .build();
得到Java代碼
void sortByLength(List<String> strings) { Collections.sort(strings, new Comparator<String>() { @Override public int compare(String a, String b) { return a.length() - b.length(); } });}
內部類構造通過內部類構造方法TypeSpec.anonymousClassBuilder("")初始化內部類,然後使用$L引用對應內部類。
添加註釋
欄位、方法、類都可以添加註釋
MethodSpec dismiss = MethodSpec.methodBuilder("dismiss") .addJavadoc("Hides {@code message} from the caller's history. Other\n" + "participants in the conversation will continue to see the\n" + "message in their own history unless they also delete it.\n") .addJavadoc("\n") .addJavadoc("<p>Use {@link #delete($T)} to delete the entire\n" + "conversation for all participants.\n", Conversation.class) .addModifiers(Modifier.PUBLIC, Modifier.ABSTRACT) .addParameter(Message.class, "message") .build();
效果
/** * Hides {@code message} from the caller's history. Other * participants in the conversation will continue to see the * message in their own history unless they also delete it. * * <p>Use {@link #delete(Conversation)} to delete the entire * conversation for all participants. */ void dismiss(Message message);
使用$T 引用類。
添加註解
使用AnnotationSpec.builder()添加註解:
MethodSpec logRecord = MethodSpec.methodBuilder("recordEvent") .addModifiers(Modifier.PUBLIC, Modifier.ABSTRACT) .addAnnotation(AnnotationSpec.builder(Headers.class) .addMember("accept", "$S", "application/json; charset=utf-8") .addMember("userAgent", "$S", "Square Cash") .build()) .addParameter(LogRecord.class, "logRecord") .returns(LogReceipt.class) .build();
效果
@Headers( accept = "application/json; charset=utf-8", userAgent = "Square Cash")LogReceipt recordEvent(LogRecord logRecord);