Home JavaPoet的使用和示例
Post
Cancel

JavaPoet的使用和示例

JavaPoet的使用和示例

JavaPoet使用面向对象的方式来构建类,其中主要分为三个部分,类,属性和方法。一般构建顺序为先属性,再方法,最后创建类的时候把前面创建的属性和方法都添加到类中即可。

导入依赖

1
implementation 'com.squareup:javapoet:1.13.0'

关键API

Type && TypeName

Type

Type表示类的基础class类型,例如常见的基础类型int.class,又或者对象类型String.classFile.class等,以及数组类型File[].class,使用这个不用手动导包,便捷方便。

TypeName

当有些库不在标准库中,而我们又不想在这个模块中引入过多的别的三方库时,我们可以使用TypeName来实现导入对应库的能力。当然可以使用Type的地方都是可以使用TypeName的。

  • 基础变量类型可以使用TypeName.BOOLEAN

  • 数组类型可以使用ArrayTypeName.of(boolean.class)又或者ArrayTypeName.of(TypeName.BOOLEAN)

  • 不能直接使用到的类可以使用ClassName.get(“java.io”, “File”)来获取TypeName并导入对应的包。当需要使用TypeName的地方也可以使用ClassName.get(File.class)来获取对呀的TypeName类型。

  • 属性支持范型,需要使用ParameterizedTypeName.get(),使用ParameterizedTypeName.get(List.class, Integer.class)可以得到List<Integer>,因为范型是不支持基础变量类型的,所以不能使用int.classTypeName.INT。当然也可以使用TypeName来构建,ParameterizedTypeName.get(ClassName.get("java.util", "Map"), TypeName.get(Integer.class), TypeName.get(String.class),这个构建比较曲折,因为在此处Type类型的并不能与TypeName进行混用。

  • 范型属性,TypeVariableName.get("T")

  • 通配符类型,这个需要用在类或者支持范型的属性中,WildcardTypeName.subtypeOf(String.class),输出? extends String

属性

构建属性使用FieldSpec,通过builder(type,name,...modifiers),可以指定属性的类型、名称以及修饰符。通过addModifiers()同样可以设置对应的修饰符。通过使用initializer()可以给属性赋初始值。通过addAnnotation()可以增加注解,具体看如下例子

基础变量属性

期望private volatile int age = 18;

1
2
3
4
5
FieldSpec age = FieldSpec.builder(int.class, "age")
        .initializer("18")
        .addModifiers(Modifier.VOLATILE)
        .addModifiers(Modifier.PRIVATE)
        .build();
通过手动设置对象路径的方式

期望public static Object lock = new Object;

1
2
3
4
5
6
FieldSpec lock = FieldSpec.builder(
                ClassName.get("java.lang", "Object"),
                "lock",
                Modifier.PUBLIC, Modifier.STATIC
        ).initializer("new Object()")
        .build();
使用Map

期望public Map<String, Integer> cacheMap;

1
2
3
4
5
6
FieldSpec name = FieldSpec.builder(
                ParameterizedTypeName.get(Map.class, String.class, Integer.class),
                "cacheMap"
        )
        .addModifiers(Modifier.PUBLIC)
        .build();
使用范型

期望private T data;,需要类也设置范型。

1
2
3
FieldSpec data = FieldSpec.builder(TypeVariableName.get("T"), "data")
        .addModifiers(Modifier.PRIVATE)
        .build();
使用通配符

期望private List<? extends String> list;

1
2
3
4
5
6
7
8
FieldSpec list = FieldSpec.builder(
                ParameterizedTypeName.get(
                        ClassName.get(List.class),
                        WildcardTypeName.subtypeOf(String.class)
                ), "list"
        )
        .addModifiers(Modifier.PRIVATE)
        .build();

方法

方法使用MethodSpec来创建。方法修饰符、注解和属性基本一致,使用addTypeVariable()来增加方法范型,returns()来设置方法返回类型,通过addParameter()增加方法入参,使用addException()来设置方法可以抛出的异常。比较困难的就是方法体里面的内容了,方法体里的内容可以使用CodeBlock来表示,最后通过addCode()方式添加。

CodeBlock

CodeBlock主要用来构建方法内容,主要添加代码的方式为addStatement()来逐行添加。同样的,MethodSpec也是可以使用这个方法的,CodeBlock主要提供一个方便的解耦方式。addStatement()提供三种代码替换的方式:

  • addStatement("$T file", File.class)=>File file;,$T表示会主动把对应的包import进来。
  • addStatement("$L = null", "file")=>file = null;,$L只是简单的替换。
  • addStatement("$S.length()", "foo")=>"foo".length();$S表示字符串替换,会带有双引号。

常规的addStatement()都会在语句的末位自动带上“;“作为结束,而在一些语句中并不需要如此,例如if语句等,这是需要用到如下语句来制定作用域。括号之间需要满足Java的支持语法规范。

  • beginControlFlow()会在代码结束为止补上"{"
  • nextControlFlow()会在代码开始钱补上"}",在开始位置补上"{".
  • endControlFlow()则会在开始位置补上"}"

对于不需要“;“"{"“}",可以直接使用addCode(String)的方式来添加,例如switch语句

代码段示例

if语句
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
/**
* if(i > 10) {
    * System.out.println("true");
* } else if(i < 10) {
    * System.out.println("false");
* } else {
    * System.out.println("undefine");
* }
*/
CodeBlock codeBlock = CodeBlock.builder()
        .beginControlFlow("if(i > 10)")
        .addStatement("System.out.println($S)", "true")
        .nextControlFlow("else if(i < 10)")
        .addStatement("System.out.println($S)", "false")
        .nextControlFlow("else")
        .addStatement("System.out.println($S)", "undefine")
        .endControlFlow()
        .build();
for循环
1
2
3
4
5
6
7
8
9
10
/**
* for (int i = 0; i < 5; i++) {
*     System.out.print("str1 value" + i);
* }
*/
CodeBlock codeBlock = CodeBlock.builder()
        .beginControlFlow("for (int i = 0; i < 5; i++)")
        .addStatement("System.out.print($S + i)", "str1 value")
        .endControlFlow()
        .build();
while语句
1
2
3
4
5
6
7
8
9
10
11
12
/**
* while(i > 10) {
*     System.out.println("currentCount: " + i);
*     i--;
* }
*/
CodeBlock codeBlock = CodeBlock.builder()
        .beginControlFlow("while(i > 10)")
        .addStatement("System.out.println($S + i)", "currentCount: ")
        .addStatement("i--")
        .endControlFlow()
        .build();
do while语句
1
2
3
4
5
6
/**
* do {
* } while (i > 10);
*/
do {
} while (i > 10);
try catch语句
1
2
3
4
5
6
7
8
9
10
11
12
13
14
/**
* try {
* } catch (Exception e) {
    * e.printStackTrace();
* } finally {
* }
*/
CodeBlock codeBlock = CodeBlock.builder()
        .beginControlFlow("try")
        .nextControlFlow("catch ($T e)", Exception.class)
        .addStatement("e.printStackTrace()")
        .nextControlFlow("finally")
        .endControlFlow()
        .build();

类使用TypeSpec来创建。修饰符、范型都与方法是一样的。另外还可以使用addMethod()来添加方法,addField()来增加属性。

正常类
1
2
3
4
5
6
7
/*
 * public class Main {
 * }
 */
TypeSpec typeSpec = TypeSpec.classBuilder("Main")
        .addModifiers(Modifier.PUBLIC)
        .build();
枚举类
1
2
3
4
5
6
7
8
/*
 * enum Main {
 *   DEMO
 * }
 */
TypeSpec typeSpec = TypeSpec.enumBuilder("Main")
        .addEnumConstant("DEMO")
        .build();
注解类
1
2
3
4
5
6
/*
 * @interface Main {
 * }
 */
TypeSpec typeSpec = TypeSpec.annotationBuilder("Main")
        .build();
接口
1
2
3
4
5
6
/*
 * interface Main {
 * }
 */
TypeSpec typeSpec = TypeSpec.interfaceBuilder("Main")
        .build();
匿名内部类
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
//  void test() {
//    new Thread(new Runnable() {
//      @Override
//      public void run() {
//      }
//    });;
//  }

TypeSpec typeSpec = TypeSpec.anonymousClassBuilder("")
        .superclass(Runnable.class)
        .addMethod(
                MethodSpec.methodBuilder("run")
                        .addModifiers(Modifier.PUBLIC)
                        .addAnnotation(Override.class)
                        .build()
        )
        .build();

MethodSpec methodSpec = MethodSpec
        .methodBuilder("test")
        .addStatement("new $T($L);", Thread.class, typeSpec)
        .build();

参考文档

This post is licensed under CC BY 4.0 by the author.