https://github.com/979451341/TestAPT
这篇说如何生成Java文件,所使用的就是JavaPoet这个API提供的代码,让我们来学习如何去使用它。
1.添加定死的代码
比如我想要生成如下代码的java文件
package com.example;
public final class TestClass {
void main() {
int total = 0;
for (int i = 0; i < 10; i++) {
total += i;
}
}
}
那生成代码如下
MethodSpec main = MethodSpec.methodBuilder("main")
.addCode(""
+ "int total = 0;\n"
+ "for (int i = 0; i < 10; i++) {\n"
+ " total += i;\n"
+ "}\n")
.build();
TypeSpec testClass = TypeSpec.classBuilder("TestClass")
.addModifiers(Modifier.PUBLIC,Modifier.FINAL)
.addMethod(main)
.build();
JavaFile javaFile = JavaFile.builder("com.example",testClass)
.build();
通过以上代码可以看出,JavaPoet很多时候都是用的Builder模式来构建代码,这个MethodSpec是用来新建函数的,通过methodBuilder取函数名并通过addCode来添加代码,TypeSpec则是用来生成类,通过classBuilder来创建和去类名,通过addModifiers来规定类的属性,然后通过addMethod添加函数。最后是通过JavaFile来生成相应包下的java文件,指定了包名和类。
后面我会重点说MethodSpec如何用,就不贴完整代码了
2.引用自己给参数
以上代码还有另一种方法生成,addStatement() 负责分号和换行,beginControlFlow() + endControlFlow() 需要一起使用,相当于{ }
MethodSpec main = MethodSpec.methodBuilder("main")
.addStatement("int total = 0")
.beginControlFlow("for (int i = 0; i < 10; i++)")
.addStatement("total += i")
.endControlFlow()
.build();
还能给生成有参数的函数
private MethodSpec computeRange(String name, int from, int to, int op) {
return MethodSpec.methodBuilder(name)
.returns(int.class)
.addStatement("int result = 0")
.beginControlFlow("for (int i = " + from + "; i < " + to + "; i++)")
.addStatement("result = result +" + op + "+ i")
.endControlFlow()
.addStatement("return result")
.build();
}
还有另一种生成有参数的函数,Literals 直接写在输出代码中,没有转义。 它的类型可以是所有基础类型。
private MethodSpec computeRange(String name, int from, int to, int op) {
return MethodSpec.methodBuilder(name)
.returns(int.class)
.addStatement("int result = 0")
.beginControlFlow("for (int i = $L; i < $L; i++)", from, to)
.addStatement("result = result + $L+ i", op)
.endControlFlow()
.addStatement("return result")
.build();
}
然后$S 表示可以一个 string
private static MethodSpec whatsMyName(String name) {
return MethodSpec.methodBuilder(name)
.returns(String.class)
.addStatement("return $S", name)
.build();
}
3.导包
通过 $T 进行映射,会自动import声明
MethodSpec today = MethodSpec.methodBuilder("today")
.returns(Date.class)
.addStatement("return new $T()", Date.class)
.build();
ClassName 可以识别任何声明类。具体看下面的例子:
ClassName hoverboard = ClassName.get("com.mattel", "Hoverboard");
ClassName list = ClassName.get("java.util", "List");
ClassName arrayList = ClassName.get("java.util", "ArrayList");
TypeName listOfHoverboards = ParameterizedTypeName.get(list, hoverboard);
MethodSpec beyond = MethodSpec.methodBuilder("beyond")
.returns(listOfHoverboards)
.addStatement("$T result = new $T<>()", listOfHoverboards, arrayList)
.addStatement("result.add(new $T())", hoverboard)
.addStatement("result.add(new $T())", hoverboard)
.addStatement("result.add(new $T())", hoverboard)
.addStatement("return result")
.build();
还有import static
ClassName namedBoards = ClassName.get("com.mattel", "Hoverboard", "Boards");
import static com.mattel.Hoverboard.Boards.*;
还有生成的函数引用自己生成的函数
通过$N来引用 hexDigit()方法作为一个参数:
addStatement("result[1] = $N(1)", hexDigit)
4.构造函数
addParameter(String.class, "greeting")
public HelloWorld(String greeting)
还可以指定类型
addParameter(String.class, "robot", Modifier.FINAL)
5.成员变量Fields
FieldSpec android = FieldSpec.builder(String.class, "android")
.addModifiers(Modifier.PRIVATE, Modifier.FINAL)
.build();
TypeSpec helloWorld = TypeSpec.classBuilder("HelloWorld")
.addModifiers(Modifier.PUBLIC)
.addField(android)
.addField(String.class, "robot", Modifier.PRIVATE, Modifier.FINAL)
.build();
public class HelloWorld {
private final String android;
private final String robot;
}
6.接口
TypeSpec helloWorld = TypeSpec.interfaceBuilder("HelloWorld")
.addModifiers(Modifier.PUBLIC)
.build();
7.枚举
TypeSpec helloWorld = TypeSpec.enumBuilder("Roshambo")
.addModifiers(Modifier.PUBLIC)
.addEnumConstant("ROCK")
.addEnumConstant("SCISSORS")
.addEnumConstant("PAPER")
.build();
参考文章
http://blog.csdn.net/crazy1235/article/details/51876192