Javapoet
1. 简介
1.1 什么是javapoet
pote 即诗人,也就是写文字的人,而javapet也就是使用java来作诗的人。而在Java的世界里,“诗”就是java的源代码。因此,javppoet就是来帮助我们来生成Java源代码的工具。这一点在使用编译时注解来帮助我们自动生成一些类提供了很大的遍历。下面就让我们来看看这位诗人是如何来写出优美的“诗句”的。
1.2 导入javapoet
本文是在android studio 环境下开发的,需要导入相应的依赖
compile 'com.squareup:javapoet:1.7.0'
2. javapoet 的使用
2.1 javapoet 中的相关知识点
2.1.1 几个常用的类
- MethodSpec 代表一个构造函数或方法声明。
- TypeSpec 代表一个类,接口,或者枚举声明
- FieldSpec 代表一个成员变量,一个字段声明。
- JavaFile包含一个顶级类的Java文件。
- ParameterSpec 用来创建参数
- AnnotationSpec 用来创建注解
- TypeName 类型,如在添加返回值类型是使用 TypeName.VOID
- ClassName 用来包装一个类
2.1.2 javapoet 常用的API
- addStatement() 方法负责分号和换行
- beginControlFlow() + endControlFlow() 需要一起使用,提供换行符和缩进。
- addCode() 以字符串的形式添加内
- returns 添加返回值类型
- .constructorBuilder() 生成构造器函数
- .addAnnotation 添加注解
- addSuperinterface 给类添加实现的接口
- superclass 给类添加继承的父类
- ClassName.bestGuess(“类全名称”) 返回ClassName对象,这里的类全名称表示的类必须要存在,会自动导入相应的包
- ClassName.get(“包名”,”类名”) 返回ClassName对象,不检查该类是否存在
- TypeSpec.interfaceBuilder(“HelloWorld”)生成一个HelloWorld接口
- MethodSpec.constructorBuilder() 构造器
- addTypeVariable(TypeVariableName.get(“T”, typeClassName))
会给生成的类加上泛型
2.1.3 占位符
- $L代表的是字面量
- $S for Strings
- $N for Names(我们自己生成的方法名或者变量名等等)
- $T for Types
这里的$T,在生成的源代码里面,也会自动导入你的类。
这些点可以在阅读下面的代码时作为参考
2.2 入门 Hello World
通过javapoet 来生成一个带有mian方法并且在mian方法中在控制台输出”hello world” 的类
`
public static void main(String[] args) throws IOException {
MethodSpec main = MethodSpec
.methodBuilder("main") //添加方法的名称
.addModifiers(Modifier.PUBLIC, Modifier.STATIC) //方法修饰的关键字
.addParameter(String[].class, "args") //添加方法的参数
.addStatement("$T.out.println($S)", System.class, "hello world") //添加代码
.build();
TypeSpec hello = TypeSpec.classBuilder("HelloWorld") //添加类的名称
.addModifiers(Modifier.PUBLIC) //添加修饰的关键字
.addMethod(main) //添加该类中的方法
.build();
String packgeName = "com.zs.javapoet" //生成类的包名
JavaFile file = JavaFile.builder(packgeName, hello).build(); //在控制台输出
file.writeTo(System.out);
}
输出结果
`
package com.zs.javapoet;
import java.lang.String;
import java.lang.System;
public class HelloWorld {
public static void main(String[] args) {
System.out.println("hello world");
}
}
`
2.3 具体使用
2.3.1 创建参数 添加多个参数 添加多个方法
`ParameterSpec parameterSpec = ParameterSpec.builder(Integer.class,
"page", Modifier.FINAL).build(); // 创建参数
MethodSpec meth1 = MethodSpec.methodBuilder("meth1")
.addModifiers(Modifier.PUBLIC, Modifier.STATIC)
.addParameter(String[].class, "args") // 添加多个参数
.addParameter(parameterSpec)
.addStatement("$T.out.println($S)", System.class, "hello world")
.build();
MethodSpec meth2 = MethodSpec
.methodBuilder("meth2")
.addModifiers(Modifier.PUBLIC, Modifier.STATIC)
.addParameter(Long.class, "price")
.addStatement("$T.out.println($S)", System.class, "hello world")
.build();
TypeSpec class1 = TypeSpec.classBuilder("HelloWorld")
.addModifiers(Modifier.PUBLIC)
.addMethod(meth1) // 在一个类中添加多个方法
.addMethod(meth2).build();
JavaFile file = JavaFile.builder("com.zs.javapoet", class1).build(); // 在控制台输出
file.writeTo(System.out);
`
生成结果
`package com.zs.javapoet;
import java.lang.Integer;
import java.lang.Long;
import java.lang.String;
import java.lang.System;
public class HelloWorld {
public static void meth1(String[] args, final Integer page) {
System.out.println("hello world");
}
public static void meth2(Long price) {
System.out.println("hello world");
}
}
`
2.3.2 if 语句
` MethodSpec meth2 = MethodSpec
.methodBuilder("meth2")
.addModifiers(Modifier.PUBLIC, Modifier.STATIC)
.addParameter(Long.class, "price")
.beginControlFlow(" if (price < 5 ) ")
.addStatement("price =5 ")
.endControlFlow()
.build();
TypeSpec class1 = TypeSpec.classBuilder("HelloWorld")
.addModifiers(Modifier.PUBLIC)
.addMethod(meth2).build();
JavaFile file = JavaFile.builder("com.zs.javapoet", class1).build();
file.writeTo(System.out);`
结果为
`package com.zs.javapoet;
import java.lang.Long;
public class HelloWorld {
public static void meth2(Long price) {
if (price < 5 ) {
price =5 ;
}
}
}
`#### 2.3.2 while 语句 和 $L
$L可以代替常量占据位置
` int endCondition =40; // 定义一个常量
MethodSpec meth2 = MethodSpec
.methodBuilder("meth2")
.addModifiers(Modifier.PUBLIC, Modifier.STATIC)
.addParameter(Long.class, "endCondition")
.addStatement("int i=0")
.beginControlFlow(" while (price < $L ) ",endCondition) // $L可以代替常量占据位置 beginControlFlow会在该语句后自动加上{
.addStatement(" i++ ")
.endControlFlow()
.build();
TypeSpec class1 = TypeSpec.classBuilder("HelloWorld")
.addModifiers(Modifier.PUBLIC)
.addMethod(meth2).build();
JavaFile file = JavaFile.builder("com.zs.javapoet", class1).build();
file.writeTo(System.out);`
结果
`package com.zs.javapoet;
import java.lang.Long;
public class HelloWorld {
public static void meth2(Long endCondition) {
int i=0;
while (price < 40 ) {
i++ ;
}
}
}
2.3.3 for 语句 和 $S
$S 可以代替String类型占据位置
` int from = 0;
int to = 10;
String outPut = "$S代表String";
MethodSpec meth2 = MethodSpec
.methodBuilder("meth2")
.addModifiers(Modifier.PUBLIC, Modifier.STATIC)
.beginControlFlow(" for (int i=$L ; i < $L ; i++) ",from,to)
.addStatement("System.out.println($S)",outPut) //$S 可以代替String类型占据位置
.endControlFlow()
.build();
TypeSpec class1 = TypeSpec.classBuilder("HelloWorld")
.addModifiers(Modifier.PUBLIC)
.addMethod(meth2).build();
JavaFile file = JavaFile.builder("com.zs.javapoet", class1).build();
file.writeTo(System.out);
结果
`package com.zs.javapoet;
public class HelloWorld {
public static void meth2() {
for (int i=0 ; i < 10 ; i++) {
System.out.println("$S代表String");
}
}
}
`
2.3.4 $T
$T,在生成的源代码里面,也会自动导入你的类。
`MethodSpec today = MethodSpec.methodBuilder("today")
.returns(Date.class)
.addStatement("return new $T()", Date.class)
.build();
TypeSpec helloWorld = TypeSpec.classBuilder("HelloWorld")
.addModifiers(Modifier.PUBLIC, Modifier.FINAL)
.addMethod(today)
.build();
JavaFile javaFile = JavaFile.builder("com.example.helloworld", helloWorld)
.build();
javaFile.writeTo(System.out);`
结果
`package com.example.helloworld;
import java.util.Date;
public final class HelloWorld {
Date today() {
return new Date();
}
}`
2.3.5 $N
在生成的代码中通常要调用另一个方法,可以使用$N 来代替另一个方法
` MethodSpec add = MethodSpec.methodBuilder("add")
.addModifiers(Modifier.PUBLIC).addParameter(Integer.class, "i")
.returns(Integer.class).addStatement("return i+1").build();
MethodSpec useAdd = MethodSpec.methodBuilder("usePrint")
.addModifiers(Modifier.PUBLIC).addStatement("int i=0")
.addStatement("i=$N(i)", add).build();
TypeSpec class1 = TypeSpec.classBuilder("HelloWorld")
.addModifiers(Modifier.PUBLIC).addMethod(add).addMethod(useAdd)
.build();
JavaFile file = JavaFile.builder("com.zs.javapoet", class1).build();
file.writeTo(System.out);
`
生成的代码
`
package com.zs.javapoet;
import java.lang.Integer;
public class HelloWorld {
public Integer add(Integer i) {
return i+1;
}
public void usePrint() {
int i=0;
i=add(i);
}
}
`
$N 也可代替定义的变量
`MethodSpec flux = MethodSpec.constructorBuilder()
.addModifiers(Modifier.PUBLIC)
.addParameter(String.class, "greeting")
.addStatement("this.$N = $N", "greeting", "greeting")
.build();
TypeSpec helloWorld = TypeSpec.classBuilder("HelloWorld")
.addModifiers(Modifier.PUBLIC)
.addField(String.class, "greeting", Modifier.PRIVATE, Modifier.FINAL)
.addMethod(flux)
.build();`
生成的代码
`public class HelloWorld {
private final String greeting;
public HelloWorld(String greeting) {
this.greeting = greeting;
}
}`
2.3.6 AnnotationSpec
`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);`
2.3.7 javadoc
`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);`
2.3.8 继承父类实现接口
接口代码
package com.zs.javapoet;
public interface TestInterface<T> {
void test(T testPara);
}
父类代码
package com.zs.javapoet.test;
public class TestExtendesClass {
}
使用javapoet 生成一个实现TestInterface,并且继承TestExtendesClass 的类
final ClassName InterfaceName = ClassName.get("com.zs.javapoet","TestInterface");
ClassName superinterface = ClassName.bestGuess("com.zs.javapoet.TestClass");
//ClassName superinterface = ClassName.get("com.zs.javapoet","aa");
TypeSpec.Builder spec = TypeSpec.classBuilder("TestImpl")
.addModifiers(Modifier.PUBLIC)
// 添加接口,ParameterizedTypeName的参数1是接口,参数2是接口的泛型
.addSuperinterface(ParameterizedTypeName.get(InterfaceName, superinterface))
//使用ClassName.bestGuess会自动导入包
.superclass(ClassName.bestGuess("com.zs.javapoet.test.TestExtendesClass"));
MethodSpec.Builder methodSpec = MethodSpec.methodBuilder("test")
.addAnnotation(Override.class)
.returns(TypeName.VOID)
.addParameter(superinterface, "testPara")
.addStatement("System.out.println(hello)" );
TypeSpec typeSpec = spec.addMethod(methodSpec.build()).build();
JavaFile file = JavaFile.builder("com.zs.javapoet", typeSpec).build();
file.writeTo(System.out);
生成的代码
package com.zs.javapoet;
import com.zs.javapoet.test.TestExtendesClass;
import java.lang.Override;
public class TestImpl extends TestExtendesClass implements TestInterface<TestClass> {
@Override
void test(TestClass testPara) {
System.out.println(hello);
}
}
3 参考资料
https://github.com/square/javapoet
http://blog.csdn.net/rainbow88888/article/details/51458412?locationNum=3