JavaPoet介绍
JavaPoet 是 Square 公司开发的一个开源 Java 库,用于通过 Java 代码生成器来创建和修改 Java 代码。它的目标是通过编程的方式生成 Java 代码,以简化代码生成的过程,避免手动拼接字符串等繁琐的操作。JavaPoet 可以用于生成类、方法、字段、注解等各种 Java 代码结构。
JavaPoet特点:
- 类型安全: JavaPoet 使用了类型安全的 API,避免了在生成代码时出现类型错误。
- 易于使用: JavaPoet 提供了简洁的 API,使得生成代码变得直观且易于理解。
- 代码清晰: 生成的代码具有良好的可读性,不需要手动处理字符串拼接。
- 支持链式调用: JavaPoet 的 API 支持链式调用,可以方便地组合多个操作。
源文件元素
TypeSpec、ParameterSpec、MethodSpec、CodeBlock、JavaFile都是JavaPoet提供的用于描述一个源文件元素的类。
TypeSpec代表了一个接口、类、注解、枚举的定义。你可以使用它来定义类的修饰符、字段、方法等。// 类生成: TypeSpec.classBuilder("HelloWorld") //接口: TypeSpec.interfaceBuilder("HelloWorld")ParameterSpec代表一个成员变量、函数参数的定义。它包含参数的类型、名称和修饰符等信息。ParameterSpec parameterSpec = ParameterSpec.builder(String.class, "message") .addModifiers(Modifier.FINAL) .build();MethodSpec代表了方法的定义。你可以使用它来定义方法的修饰符、返回类型、参数、代码块等。MethodSpec methodSpec = MethodSpec.methodBuilder("greet") .addModifiers(Modifier.PUBLIC) .returns(void.class) .addParameter(parameterSpec) .addStatement("$T.out.println($S + $N)", System.class, "Message: ", "message") .build();CodelBlock用于描述一段代码块。你可以在其中添加多个语句、变量、表达式等。CodeBlock codeBlock = CodeBlock.builder() .addStatement("$T.out.println($S)", System.class, "Hello, JavaPoet!") .addStatement("int sum = $L + $L", 5, 3) .build();JavaFile表示源文件本身。一个java文件正式通过以上几种类型的嵌套、组合,最终描述成一个完整的java源文件。JavaFile javaFile = JavaFile.builder("com.example", helloWorld) .addStaticImport(System.class, "out") .build();
通过这些 API,我们可以以编程方式构建 Java 代码元素,并将它们组合成类、方法等结构。最后,可以使用 JavaFile 将生成的代码写入文件中。
JavaPoet占位符
在 JavaPoet 中,这些符号 $L、$S、$T、$N 等被称为代码占位符,它们用于在生成代码时插入不同类型的值。下面是这些代码占位符的含义和用法:
| 符号 | 含义 | 示例 |
|---|---|---|
$L | 字面量 | .addStatement("int x = $L", 42) |
$S | 字符串 | .addStatement("$T.out.println($S)", System.class, "Hello") |
$T | 类型 | .addStatement("$T value = $L", String.class, "hello") |
$N | 名称(变量、方法等) | .addStatement("int $N = 0", "count") |
这些代码占位符允许你在生成代码时将变量、字符串、类型等值插入到代码中,而不需要手动拼接字符串,从而避免了一些常见的错误和繁琐的操作。
例如,在 .addStatement("$T.out.println($S)", System.class, "Hello") 这个代码中,$T 表示类型(System.class),$S 表示字符串("Hello")。
Javapoet示例
引入依赖
<dependency>
<groupId>com.squareup</groupId>
<artifactId>javapoet</artifactId>
<version>1.13.0</version>
</dependency>
生成一个main方法,输出‘Hello, JavaPoet!’
public static void main(String[] args) throws IOException {
// 创建一个方法
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();
// 创建一个 Java 文件
JavaFile javaFile = JavaFile.*builder*("com.example.helloworld", helloWorld)
.build();
// 将生成的代码写入文件
javaFile.writeTo(System.*out*);
}
生成代码如下:
package com.example.helloworld;
import java.lang.String;
import java.lang.System;
public final class HelloWorld {
public static void main(String[] args) {
System.out.println("Hello, JavaPoet!");
}
}
静态方法引入示例
JavaPoet支持静态导入。它通过显式收集类型成员名来实现。
ClassName namedBoards = ClassName.get("com.mattel", "Hoverboard", "Boards");
MethodSpec beyond = MethodSpec.methodBuilder("beyond")
.returns(listOfHoverboards)
.addStatement("$T result = new $T<>()", listOfHoverboards, arrayList)
.addStatement("result.add($T.createNimbus(2000))", hoverboard)
.addStatement("result.add($T.createNimbus(\"2001\"))", hoverboard)
.addStatement("result.add($T.createNimbus($T.THUNDERBOLT))", hoverboard, namedBoards)
.addStatement("$T.sort(result)", Collections.class)
.addStatement("return result.isEmpty() ? $T.emptyList() : result", Collections.class)
.build();
TypeSpec hello = TypeSpec.classBuilder("HelloWorld")
.addMethod(beyond)
.build();
JavaFile.builder("com.example.helloworld", hello)
.addStaticImport(hoverboard, "createNimbus")
.addStaticImport(namedBoards, "*")
.addStaticImport(Collections.class, "*")
.build();
输出结果如下:
package com.example.helloworld;
import static com.mattel.Hoverboard.Boards.*;
import static com.mattel.Hoverboard.createNimbus;
import static java.util.Collections.*;
import com.mattel.Hoverboard;
import java.util.ArrayList;
import java.util.List;
class HelloWorld {
List<Hoverboard> beyond() {
List<Hoverboard> result = new ArrayList<>();
result.add(createNimbus(2000));
result.add(createNimbus("2001"));
result.add(createNimbus(THUNDERBOLT));
sort(result);
return result.isEmpty() ? emptyList() : result;
}
}
更多示例可以参考官方文档。