Android 编译时代码生成技术探究 二 JavaPoet生成 .java源文件的Java API

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

你可能感兴趣的:(Android 编译时代码生成技术探究 二 JavaPoet生成 .java源文件的Java API)