JavaPoet 用来生成 .java 文件,本文介绍它的用法。
JavaPoet 官方文档:https://github.com/square/javapoet
implementation ‘com.squareup:javapoet:1.11.1’
直接在 Android Studio 新建项目的 build.gradle 引入,使用时找不到 javax.lang.model.element.Modifier
类,因为 android sdk (基于 OpenJDK)里没有 javax.lang.model
包。
所以要在 java library 中引入并使用。
生成这样第一个 java 文件:
package com.example.helloworld;
public final class HelloWorld {
public static void main(String[] args) {
System.out.println("Hello, JavaPoet!");
}
}
生成代码:
MethodSpec main = MethodSpec.methodBuilder("main")
.addModifiers(Modifier.PUBLIC, Modifier.STATIC)
.returns(void.class)
.addParameter(String[].class, "args")
.addStatement("$T.out.println($S)", System.class, "Hello, JavaPoet!")
.build();
TypeSpec helloWorld = TypeSpec.classBuilder("HelloWorld")
.addModifiers(Modifier.PUBLIC, Modifier.FINAL)
.addMethod(main)
.build();
JavaFile javaFile = JavaFile.builder("com.gdeer.lib", helloWorld)
.build();
javaFile.writeTo(System.out);
即 if、else、for。
要生成这样的代码:
int calculate() {
int total = 0;
for (int i = 0; i < 10; i++) {
total += i;
}
return total;
}
可以这样:
MethodSpec calculate = MethodSpec.methodBuilder("calculate")
.returns(int.class)
.addCode(""
+ "int total = 0;\n"
+ "for (int i = 0; i < 10; i++) {\n"
+ " total += i;\n"
+ "}\n"
+ "return total;\n")
.build();
也可以这样:
MethodSpec calculate1 = MethodSpec.methodBuilder("calculate1")
.returns(int.class)
.addStatement("int total = 0")
.beginControlFlow("for (int i = 0; i < 10; i++)")
.addStatement("total += i")
.endControlFlow()
.build();
addStatement
会给语句后加上;\n
beginControlFlow
会给语句加上{\n
endControlFlow
会添加一行}\n
$L 相当于 String.format 中 %s 一样,将指定的字符串替换到 $L的地方。
$S 相当于给 $L 加上一对引号。
addStatement("$T.out.println($L)", System.class, 234)
addStatement("$T.out.println($S)", System.class, 234)
生成的内容为:
System.out.println(234);
System.out.println("234");
在 JavaPoet 代指的是TypeName,该模板主要将 Class 抽象出来,用传入的 TypeName 指向的 Class 来代替。
ClassName bundle = ClassName.get("android.os", "Bundle");
addStatement("$T bundle = new $T()", bundle)
生成的内容为:
Bundle bundle = new Bundle();
$N 代指一个名称,例如调用的方法名称,变量名称。
当 $N 的字面值和其代表的值一致时,相当于 $L。
MethodSpec printAInternal = MethodSpec.methodBuilder("printAInternal")
.addStatement("$T.out.println('a')", System.class)
.build();
MethodSpec printA = MethodSpec.methodBuilder("byteToHex")
.addStatement("$N()", printAInternal)
.build();
生成的内容为:
void printAInternal() {
System.out.println('a');
}
void byteToHex() {
printAInternal();
}