Java代码生成框架-JavaPoet

介绍

      JavaPoet是用于生成.Java源文件的Java API。

         当处理诸如注释处理或与元数据文件交互(例如,数据库模式、协议格式)时,源文件生成可能非常有用。通过生成代码,您消除了编写样板文件的需要,同时也保留了元数据的单一来源。


集成到项目中

    
<!-- https://mvnrepository.com/artifact/com.squareup/javapoet -->
        <dependency>
            <groupId>com.squareup</groupId>
            <artifactId>javapoet</artifactId>
            <version>1.11.0</version>
        </dependency>


代码生成

    类

           
        //生成类
        TypeSpec helloWorld=TypeSpec.classBuilder("HelloWorld")
                .build();
        //Java文件生成
        JavaFile javaFile=JavaFile.builder("com.itcast.lyc",helloWorld).build();

        try {
            //把文件内容写入到 窗口打印出来
            javaFile.writeTo(System.out);
        } catch (IOException e) {
            e.printStackTrace();
        }

     生成内容如下:

package com.itcast.lyc;

class HelloWorld {
}

     方法

           普通的方法列子

        //生成类构造器
        TypeSpec.Builder helloWorldBuilder=TypeSpec.classBuilder("HelloWorld");

        MethodSpec main=MethodSpec.methodBuilder("main")//方法的构造器
                .addParameter(String[].class,"args")//添加参数
                .returns(void.class)//添加返回值
                .addStatement("$T.out.println($S)",System.class,"helloWorld")//添加内容
                .addStatement("$T.out.println($L)",System.class,100L)//显示字符
                .build();

        TypeSpec helloWorld=helloWorldBuilder.addMethod(main).build();

        //Java文件生成
        JavaFile javaFile=JavaFile.builder("com.itcast.lyc",helloWorld).build();

        try {
            //把文件内容写入到 窗口打印出来
            javaFile.writeTo(System.out);
        } catch (IOException e) {
            e.printStackTrace();
        }

其中$T代表类的.class类,使用$T和adddStatement匹配能自动导入包,$S表示注入字符串,adddStatement的一种注入字符串格式的语法,会自动帮语句添加分号和换行符,另外还有$L表示数字类型。

生成代码如下:

package com.itcast.lyc;

import java.lang.String;
import java.lang.System;

class HelloWorld {
  void main(String[] args) {
    System.out.println("helloWorld");
    System.out.println(100);
  }
}

方法添加代码的方式还有.addCode("asdasds;\n"),但是.addCode不会自动生成分号和换行,所以也不用,还可以这样写.addCode(CodeBlock.builder().addStatement("$S","|sdsad").build())

        控制流

    JavaPoet为生成控制流,给我们提供了便利的API,比如,我们想生成如下内容:

if (true){
   System.out.println("ok");
}

我们很难想像如果让我们自己打印{}括号带来的麻烦,所以JavaPoet在方法构造器中提供了beginControlFlow和endControlFlow。

  MethodSpec main=MethodSpec.methodBuilder("main")//方法的构造器
                .addParameter(String[].class,"args")//添加参数
                .returns(void.class)//添加返回值
                .addStatement("$T.out.println($S)",System.class,"helloWorld")//添加内容
                .addStatement("$T.out.println($L)",System.class,100L)//显示字符
                .beginControlFlow("if(true)")//控制流开始
                .addStatement("$T.out.println($S)",System.class,"ok")
                .endControlFlow()//控制流结束
                .build();

抽象类

 MethodSpec abstractMethon=MethodSpec.methodBuilder("testAbs")
                .addModifiers(Modifier.PUBLIC,Modifier.ABSTRACT)
                .build();

        TypeSpec typeSpec=TypeSpec.classBuilder("TestAbs")
                .addModifiers(Modifier.PUBLIC,Modifier.ABSTRACT)
                .addMethod(abstractMethon)
                .build();

接口类

   MethodSpec abstractMethon=MethodSpec.methodBuilder("testInterfaces")
                .addModifiers(Modifier.PUBLIC,Modifier.ABSTRACT)
                .build();

        TypeSpec typeSpec=TypeSpec.interfaceBuilder("TestInterfaces")
                .addModifiers(Modifier.PUBLIC)
                .addField(FieldSpec.builder(String.class,"ONLY_ONCE")
                          .addModifiers(Modifier.PUBLIC,Modifier.STATIC,Modifier.FINAL)
                          .initializer("$S","OKKK")
                          .build())
                //添加字段
                .addMethod(abstractMethon)
                .build();

 构造方法

      //构造方法
        MethodSpec consructorMethod=MethodSpec.constructorBuilder()
                .addModifiers(Modifier.PUBLIC)
                .addParameter(Integer.class,"age")//参数
                .addStatement("this.$N=$N","age","age")//添加样式代码$N表示当前类的引用
                .build();

        TypeSpec helloWorld= helloWorldBuilder
                .addMethod(main)//添加main方法
                .addField(FieldSpec.builder(Integer.class,"age").addModifiers(Modifier.PRIVATE).build())//添加字段
                .addMethod(consructorMethod)//添加构造方法
                .build();

添加参数

     
.addParameter(Integer.class,"age")//参数
  
 ParameterizedTypeName parameterizedTypeNameMap=ParameterizedTypeName.get(
                ClassName.get(Map.class),
                ClassName.get(Integer.class),
                ParameterizedTypeName.get(
                        ClassName.get(Class.class),
                        WildcardTypeName.subtypeOf(ClassName.get(Object.class))
                )
        );

        ParameterizedTypeName parameterizedTypeNameList=ParameterizedTypeName.get(
                ClassName.get(List.class),
                WildcardTypeName.subtypeOf(ClassName.get(Integer.class))
        );

        //添加带参数的方法
        MethodSpec parmMethod=MethodSpec.methodBuilder("welomeBeiJing")
                .addParameter(String.class,"parm")
                .addParameter(ParameterSpec.builder(parameterizedTypeNameMap,"map").build())
                .addParameter(ParameterSpec.builder(parameterizedTypeNameList,"list").build())
                .build();
最后生成效果:
 void welomeBeiJing(String parm, Map<Integer, Class<?>> map, List<? extends Integer> list) {
  }
    需要生成通配符的参数 使用 

.addParameter(ParameterSpec.builder(TypeVariableName.get("T"),"t").build())
下面引用别人的图 加深理解: 点击打开链接



添加字段

 .addField(FieldSpec.builder(Integer.class,"age").addModifiers(Modifier.PRIVATE).build())//添加字段

Enums

File file=new File(System.getProperty("user.dir"),"\\src\\main\\java");


        TypeSpec typeSpec=TypeSpec.enumBuilder("EnumsTest")
                .addModifiers(Modifier.PUBLIC)
                .addEnumConstant("Rock",TypeSpec.anonymousClassBuilder("$S","Page")
                            .addMethod(MethodSpec.methodBuilder("toString")
                                    .addAnnotation(Override.class)
                                    .addModifiers(Modifier.PUBLIC)
                                    .addStatement("return $S","avalanche")
                                    .returns(String.class)
                                    .build())
                        .build())
                .addEnumConstant("Sci",TypeSpec.anonymousClassBuilder("$S","ssss").build())
                .addEnumConstant("Apple",TypeSpec.anonymousClassBuilder("$S","sad").build())
                .addField(String.class,"hand",Modifier.PRIVATE,Modifier.FINAL)
                .addMethod(MethodSpec.constructorBuilder()
                          .addParameter(String.class,"hand")
                          .addStatement("this.$N=$N","hand","hand").build())
                .build();

        JavaFile javaFile=JavaFile.builder("com.itcast.lyc.javapoet",typeSpec).build();

        javaFile.writeTo(file);
  生成代码:
package com.itcast.lyc.javapoet;

import java.lang.Override;
import java.lang.String;

public enum EnumsTest {
  Rock("Page") {
    @Override
    public String toString() {
      return "avalanche";
    }
  },

  Sci("ssss"),

  Apple("sad");

  private final String hand;

  EnumsTest(String hand) {
    this.hand=hand;
  }
}
枚举类型通过TypeSpec.enumBuilder构造器进行添加枚举类。

内部类

TypeSpec comparator = TypeSpec.anonymousClassBuilder("")
    .addSuperinterface(ParameterizedTypeName.get(Comparator.class, String.class))
    .addMethod(MethodSpec.methodBuilder("compare")
        .addAnnotation(Override.class)
        .addModifiers(Modifier.PUBLIC)
        .addParameter(String.class, "a")
        .addParameter(String.class, "b")
        .returns(int.class)
        .addStatement("return $N.length() - $N.length()", "a", "b")
        .build())
    .build();

TypeSpec helloWorld = TypeSpec.classBuilder("HelloWorld")
    .addMethod(MethodSpec.methodBuilder("sortByLength")
        .addParameter(ParameterizedTypeName.get(List.class, String.class), "strings")
        .addStatement("$T.sort($N, $L)", Collections.class, "strings", comparator)
        .build())
    .build();

得到Java代码

void sortByLength(List<String> strings) {
  Collections.sort(strings, new Comparator<String>() {
    @Override
    public int compare(String a, String b) {
      return a.length() - b.length();
    }
  });
}

内部类构造通过内部类构造方法TypeSpec.anonymousClassBuilder("")初始化内部类,然后使用$L引用对应内部类。


添加注释

    字段、方法、类都可以添加注释

MethodSpec dismiss = MethodSpec.methodBuilder("dismiss")
    .addJavadoc("Hides {@code message} from the caller's history. Other\n"
        + "participants in the conversation will continue to see the\n"
        + "message in their own history unless they also delete it.\n")
    .addJavadoc("\n")
    .addJavadoc("<p>Use {@link #delete($T)} to delete the entire\n"
        + "conversation for all participants.\n", Conversation.class)
    .addModifiers(Modifier.PUBLIC, Modifier.ABSTRACT)
    .addParameter(Message.class, "message")
    .build();

效果

 /**
   * Hides {@code message} from the caller's history. Other
   * participants in the conversation will continue to see the
   * message in their own history unless they also delete it.
   *
   * <p>Use {@link #delete(Conversation)} to delete the entire
   * conversation for all participants.
   */
  void dismiss(Message message);

使用$T 引用类。


添加注解

使用AnnotationSpec.builder()添加注解:

MethodSpec logRecord = MethodSpec.methodBuilder("recordEvent")
    .addModifiers(Modifier.PUBLIC, Modifier.ABSTRACT)
    .addAnnotation(AnnotationSpec.builder(Headers.class)
        .addMember("accept", "$S", "application/json; charset=utf-8")
        .addMember("userAgent", "$S", "Square Cash")
        .build())
    .addParameter(LogRecord.class, "logRecord")
    .returns(LogReceipt.class)
    .build();

效果

@Headers(
    accept = "application/json; charset=utf-8",
    userAgent = "Square Cash"
)
LogReceipt recordEvent(LogRecord logRecord);

猜你喜欢

转载自blog.csdn.net/u010782846/article/details/80213939