javapoet——会写代码的“诗人”

原创 2016年08月30日 23:08:23

Javapoet

1. 简介

1.1 什么是javapoet

pote 即诗人,也就是写文字的人,而javapet也就是使用java来作诗的人。而在Java的世界里,“诗”就是java的源代码。因此,javppoet就是来帮助我们来生成Java源代码的工具。这一点在使用编译时注解来帮助我们自动生成一些类提供了很大的遍历。下面就让我们来看看这位诗人是如何来写出优美的“诗句”的。

1.2 导入javapoet

本文是在android studio 环境下开发的,需要导入相应的依赖
compile 'com.squareup:javapoet:1.7.0'

2. javapoet 的使用

2.1 javapoet 中的相关知识点

2.1.1 几个常用的类

  • MethodSpec 代表一个构造函数或方法声明。
  • TypeSpec 代表一个类,接口,或者枚举声明
  • FieldSpec 代表一个成员变量,一个字段声明。
  • JavaFile包含一个顶级类的Java文件。
  • ParameterSpec 用来创建参数
  • AnnotationSpec 用来创建注解
  • TypeName 类型,如在添加返回值类型是使用 TypeName.VOID
  • ClassName 用来包装一个类

2.1.2 javapoet 常用的API

  • addStatement() 方法负责分号和换行
  • beginControlFlow() + endControlFlow() 需要一起使用,提供换行符和缩进。
  • addCode() 以字符串的形式添加内
  • returns 添加返回值类型
  • .constructorBuilder() 生成构造器函数
  • .addAnnotation 添加注解
  • addSuperinterface 给类添加实现的接口
  • superclass 给类添加继承的父类
  • ClassName.bestGuess(“类全名称”) 返回ClassName对象,这里的类全名称表示的类必须要存在,会自动导入相应的包
  • ClassName.get(“包名”,”类名”) 返回ClassName对象,不检查该类是否存在
  • TypeSpec.interfaceBuilder(“HelloWorld”)生成一个HelloWorld接口
  • MethodSpec.constructorBuilder() 构造器
  • addTypeVariable(TypeVariableName.get(“T”, typeClassName))
    会给生成的类加上泛型

2.1.3 占位符

  • $L代表的是字面量
  • $S for Strings
  • $N for Names(我们自己生成的方法名或者变量名等等)
  • $T for Types

这里的$T,在生成的源代码里面,也会自动导入你的类。

这些点可以在阅读下面的代码时作为参考

2.2 入门 Hello World

通过javapoet 来生成一个带有mian方法并且在mian方法中在控制台输出”hello world” 的类

`
public static void main(String[] args) throws IOException {
    MethodSpec main = MethodSpec
            .methodBuilder("main") //添加方法的名称
            .addModifiers(Modifier.PUBLIC, Modifier.STATIC) //方法修饰的关键字
            .addParameter(String[].class, "args") //添加方法的参数
            .addStatement("$T.out.println($S)", System.class, "hello world") //添加代码
            .build();
    TypeSpec hello = TypeSpec.classBuilder("HelloWorld") //添加类的名称
            .addModifiers(Modifier.PUBLIC) //添加修饰的关键字
            .addMethod(main)  //添加该类中的方法
            .build(); 

           String packgeName = "com.zs.javapoet" //生成类的包名
    JavaFile file = JavaFile.builder(packgeName, hello).build(); //在控制台输出
        file.writeTo(System.out);

}

输出结果
`
package com.zs.javapoet;

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

public class HelloWorld {
  public static void main(String[] args) {
 System.out.println("hello world");
     }
 }

`

2.3 具体使用

2.3.1 创建参数 添加多个参数 添加多个方法

`ParameterSpec parameterSpec = ParameterSpec.builder(Integer.class,
            "page", Modifier.FINAL).build();  // 创建参数

    MethodSpec meth1 = MethodSpec.methodBuilder("meth1")
            .addModifiers(Modifier.PUBLIC, Modifier.STATIC)
            .addParameter(String[].class, "args") // 添加多个参数
            .addParameter(parameterSpec)
            .addStatement("$T.out.println($S)", System.class, "hello world") 
            .build();

    MethodSpec meth2 = MethodSpec
            .methodBuilder("meth2")
            .addModifiers(Modifier.PUBLIC, Modifier.STATIC)
            .addParameter(Long.class, "price")
            .addStatement("$T.out.println($S)", System.class, "hello world")
            .build();

    TypeSpec class1 = TypeSpec.classBuilder("HelloWorld")
            .addModifiers(Modifier.PUBLIC) 
            .addMethod(meth1) // 在一个类中添加多个方法
            .addMethod(meth2).build();
    JavaFile file = JavaFile.builder("com.zs.javapoet", class1).build(); // 在控制台输出
    file.writeTo(System.out);

`
生成结果

`package com.zs.javapoet;

 import java.lang.Integer;
import java.lang.Long;
import java.lang.String;
import java.lang.System;

public class HelloWorld {
  public static void meth1(String[] args, final Integer page) {
    System.out.println("hello world");
  }

  public static void meth2(Long price) {
    System.out.println("hello world");
  }
}

`

2.3.2 if 语句

`       MethodSpec meth2 = MethodSpec
            .methodBuilder("meth2")
            .addModifiers(Modifier.PUBLIC, Modifier.STATIC)
            .addParameter(Long.class, "price")
            .beginControlFlow(" if (price < 5 ) ")
            .addStatement("price =5 ")
            .endControlFlow()
            .build();

    TypeSpec class1 = TypeSpec.classBuilder("HelloWorld") 
            .addModifiers(Modifier.PUBLIC) 
            .addMethod(meth2).build();
    JavaFile file = JavaFile.builder("com.zs.javapoet", class1).build(); 
    file.writeTo(System.out);`

结果为

        `package com.zs.javapoet;

    import java.lang.Long;

    public class HelloWorld {
      public static void meth2(Long price) {
         if (price < 5 )  {
          price =5 ;
        }
      }
    }

`#### 2.3.2 while 语句 和 $L

$L可以代替常量占据位置

`       int  endCondition =40; // 定义一个常量

    MethodSpec meth2 = MethodSpec
            .methodBuilder("meth2")
            .addModifiers(Modifier.PUBLIC, Modifier.STATIC)
            .addParameter(Long.class, "endCondition")
            .addStatement("int  i=0")
            .beginControlFlow(" while (price < $L ) ",endCondition) // $L可以代替常量占据位置  beginControlFlow会在该语句后自动加上{
            .addStatement(" i++ ")
            .endControlFlow()
            .build();

    TypeSpec class1 = TypeSpec.classBuilder("HelloWorld") 
            .addModifiers(Modifier.PUBLIC) 
            .addMethod(meth2).build();
    JavaFile file = JavaFile.builder("com.zs.javapoet", class1).build(); 
    file.writeTo(System.out);`

结果
`package com.zs.javapoet;

    import java.lang.Long;

    public class HelloWorld {
      public static void meth2(Long endCondition) {
        int  i=0;
         while (price < 40 )  {
           i++ ;
        }
      }
    }

2.3.3 for 语句 和 $S

$S 可以代替String类型占据位置

`       int  from = 0;
    int to = 10;
    String outPut = "$S代表String";

    MethodSpec meth2 = MethodSpec
            .methodBuilder("meth2")
            .addModifiers(Modifier.PUBLIC, Modifier.STATIC)
            .beginControlFlow(" for (int i=$L ; i < $L ; i++) ",from,to)
            .addStatement("System.out.println($S)",outPut) //$S 可以代替String类型占据位置
            .endControlFlow()
            .build();


    TypeSpec class1 = TypeSpec.classBuilder("HelloWorld") 
            .addModifiers(Modifier.PUBLIC) 
            .addMethod(meth2).build();
    JavaFile file = JavaFile.builder("com.zs.javapoet", class1).build(); 
    file.writeTo(System.out);


结果
`package com.zs.javapoet;

public class HelloWorld {
  public static void meth2() {
     for (int i=0 ; i < 10 ; i++)  {
      System.out.println("$S代表String");
    }
  }
}

`

2.3.4 $T

$T,在生成的源代码里面,也会自动导入你的类。

`MethodSpec today = MethodSpec.methodBuilder("today")
.returns(Date.class)
.addStatement("return new $T()", Date.class)
.build();

TypeSpec helloWorld = TypeSpec.classBuilder("HelloWorld")
    .addModifiers(Modifier.PUBLIC, Modifier.FINAL)
    .addMethod(today)
    .build();

JavaFile javaFile = JavaFile.builder("com.example.helloworld", helloWorld)
    .build();

javaFile.writeTo(System.out);`

结果

`package com.example.helloworld;

    import java.util.Date;

    public final class HelloWorld {
      Date today() {
        return new Date();
      }
    }`

2.3.5 $N

在生成的代码中通常要调用另一个方法,可以使用$N 来代替另一个方法

`       MethodSpec add = MethodSpec.methodBuilder("add")
            .addModifiers(Modifier.PUBLIC).addParameter(Integer.class, "i")
            .returns(Integer.class).addStatement("return i+1").build();

    MethodSpec useAdd = MethodSpec.methodBuilder("usePrint")
            .addModifiers(Modifier.PUBLIC).addStatement("int i=0")
            .addStatement("i=$N(i)", add).build();

    TypeSpec class1 = TypeSpec.classBuilder("HelloWorld")
            .addModifiers(Modifier.PUBLIC).addMethod(add).addMethod(useAdd)
            .build();
    JavaFile file = JavaFile.builder("com.zs.javapoet", class1).build();
    file.writeTo(System.out);

`
生成的代码

`
    package com.zs.javapoet;

    import java.lang.Integer;

    public class HelloWorld {
      public Integer add(Integer i) {
        return i+1;
      }

      public void usePrint() {
        int i=0;
        i=add(i);
      }
    }

`
$N 也可代替定义的变量

        `MethodSpec flux = MethodSpec.constructorBuilder()
        .addModifiers(Modifier.PUBLIC)
        .addParameter(String.class, "greeting")
        .addStatement("this.$N = $N", "greeting", "greeting")
        .build();

    TypeSpec helloWorld = TypeSpec.classBuilder("HelloWorld")
        .addModifiers(Modifier.PUBLIC)
        .addField(String.class, "greeting", Modifier.PRIVATE, Modifier.FINAL)
        .addMethod(flux)
        .build();`

生成的代码

        `public class HelloWorld {
        private final String greeting;

      public HelloWorld(String greeting) {
        this.greeting = greeting;
      }
    }`

2.3.6 AnnotationSpec

    `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);`

2.3.7 javadoc

`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);`

2.3.8 继承父类实现接口

接口代码

package com.zs.javapoet;

public interface TestInterface<T> {
    void test(T testPara);
}

父类代码

    package com.zs.javapoet.test;

    public class TestExtendesClass {

    }

使用javapoet 生成一个实现TestInterface,并且继承TestExtendesClass 的类

    final ClassName  InterfaceName = ClassName.get("com.zs.javapoet","TestInterface");


    ClassName superinterface = ClassName.bestGuess("com.zs.javapoet.TestClass");
    //ClassName superinterface = ClassName.get("com.zs.javapoet","aa");

    TypeSpec.Builder spec = TypeSpec.classBuilder("TestImpl")
            .addModifiers(Modifier.PUBLIC)
            // 添加接口,ParameterizedTypeName的参数1是接口,参数2是接口的泛型
            .addSuperinterface(ParameterizedTypeName.get(InterfaceName, superinterface)) 
            //使用ClassName.bestGuess会自动导入包
            .superclass(ClassName.bestGuess("com.zs.javapoet.test.TestExtendesClass"));


    MethodSpec.Builder methodSpec = MethodSpec.methodBuilder("test")
            .addAnnotation(Override.class)
            .returns(TypeName.VOID)
            .addParameter(superinterface, "testPara")
            .addStatement("System.out.println(hello)" );

        TypeSpec typeSpec = spec.addMethod(methodSpec.build()).build();

    JavaFile file = JavaFile.builder("com.zs.javapoet", typeSpec).build();
    file.writeTo(System.out);

生成的代码

    package com.zs.javapoet;

    import com.zs.javapoet.test.TestExtendesClass;
    import java.lang.Override;

    public class TestImpl extends TestExtendesClass implements TestInterface<TestClass> {
      @Override
      void test(TestClass testPara) {
        System.out.println(hello);
      }
    }

3 参考资料

https://github.com/square/javapoet

http://blog.csdn.net/rainbow88888/article/details/51458412?locationNum=3

JavaPoet的基本使用

JavaPoetJavaPoet 是一个用来生成 .java源文件的Java API。当做如注解或者数据库模式、协议格式等事情时,生成源文件就比较有用处。Example以 HelloWorld 类为例...

JavaPoet - 优雅地生成代码

JavaPoet - 优雅地生成代码JavaPoet - 优雅地生成代码 一项目简介 二项目总览 1 大体结构图 2 关键类说明 三相关使用 1 API使用 2 一个简单示例 四源码浅析 五使用场景 ...

JavaPoet源码初探

JavaPoet是用于代码生成的开源编程框架,利用JavaPoet可以方便生成.java文件。代码生成技术相当于元编程,可用于编译期根据注解等元数据动态生成java类。广泛使用的dagger,butt...

自定义注解之编译时注解(RetentionPolicy.CLASS)(二)——JavaPoet

在使用编译时注解时,需要在编译期间对注解进行处理,在这里我们没办法影响程序的运行逻辑,但我们可以进行一些需处理,比如生成一些功能性代码来辅助程序的开发,最常见的是生成.java 源文件,并在程序中可以...

JavaPoet开源项目使用

JavaPoet开源项目使用JavaPoet项目可以为我们动态的生成Java文件,这是一个很强大和很动态的方法。我们使用注解的时候假如需要生成新的Java文件就可以通过这个开源项目实现。 项目地址:...

javapoet的认识

这几天接触到了javapoet的知识,总的来说就是在编译时期生成java文件。一开始刚接触到的时候,觉得很黑科技,也确实,这方面的知识,不是很了解,今天就来做点笔记,方便大家学习。 这里是square...

Android JavaPoet 动态生成Java源码(1)

转载自:http://mp.weixin.qq.com/s?__biz=MjM5NzA0ODU0NA==&mid=2247483758&idx=1&sn=0a2a36102052c54b7b2127e...
  • fwt336
  • fwt336
  • 2017年03月27日 14:48
  • 750

JavaPoet 动态生成Java源码(1)---Android

简介官方描述:JavaPoet is a Java API for generating .java source files.(JavaPoet是一个Java Api接口生成.java源码文件的工程...

编译期注解之JavaPoet

0x00 概述上一篇限于篇幅只介绍了APT,这篇来继续介绍javapoet,是square公司的开源库。正如其名,java诗人,通过注解来生成java源文件,通常要使用javapoet这个库与File...

我们为什么要用fitsSystemWindows?

原文链接:https://github.com/bboyfeiyu/android-tech-frontier/blob/master/issue-35/%E4%B8%BA%E4%BB%80%E4%B...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:javapoet——会写代码的“诗人”
举报原因:
原因补充:

(最多只允许输入30个字)