javapoet源码初识

javapoet源码初识


1.简介

android的一些比较流行的第三方库例如butterknife dagger等都是利用javapoet在编译期间生成java代码,于是抽空写一篇关于javapoet源码的文章,随笔写写。

JavaPoet是square推出的开源java代码生成框架,提供Java Api生成.java源文件。

项目主页及源码:https://github.com/square/javapoet


2.简单的设计思路

先不钻进源码的海洋,从抽象的方向来说,假如要我们写一套这样的源码,基于面向对象的设计思想,我们需要对java源文件进行抽象,我们可以先简单的抽象出好几个类。

1).最首先的应该就是java源文件本身的类,我们叫做TypeSpec,这个类代表着类,接口,枚举

2).java源文件中还有方法,我们也可以抽象一个类,叫做MethodSpec,这个类代表中构造函数或者方法。

3).FieldSpec,这个类代表着成员变量或者字段。

4).以上几个类是我们简单的对java源文件的抽象,我们还可以定义一个类用来生成java源文件,我们叫做JavaFile

通过以上简单的设计,我们可以大致写出生成java源文件的代码:

MethodSpec methodSpec = new MethodSpec(funcName,funcReturn,funcParameter ....);

FieldSpec fieldSpec = new FieldSpec(int,name,value....);

TypeSpec helloworld = new  TypeSpec(fieldSpec,methodSpec);

JavaFile javafile = new JavaFile(helloworld);

javafile.wirteTo(out);

有了个粗糙的思路,接下来我们看看javapoet中的设计。


3.javapoet设计思路(源码初探)

javapoet源码初识_第1张图片

1)Spec 用来描述Java中基本的元素,包括类型,注解,字段,方法和参数等。

      AnnotationSpec

     FieldSpec

     MethodSpec

     ParameterSpec

     TypeSpec

2)Name 用来描述类型的引用,包括Void,原始类型(int,long等)和Java类等。

      TypeName

      ArrayTypeName

     ClassName

     ParameterizedTypeName

     TypeVariableName

     WildcardTypeName

3)CodeBlock 用来描述代码块的内容,包括普通的赋值,if判断,循环判断等。

4)JavaFile 完整的Java文件,JavaPoet的主要的入口。

5)CodeWriter 读取JavaFile并转换成可阅读可编译的Java源文件。


4.举个栗子:

package com.example.helloworld;

   public final class HelloWorld {

   public static void main(String[] args) {

            System.out.println("Hello, World!");

          }

     }

我们要生成如上java源文件:

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, World!")

                                 .build();

 TypeSpec helloWorld = TypeSpec.classBuilder("HelloWorld")

                                  .addModifiers(Modifier.PUBLIC, Modifier.FINAL)

                                  .addMethod(main)

                                  .build();

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

                                  .build();

javaFile.writeTo(System.out);

乍一看跟我们第二点简单的设计思路有丢丢像,不过类中的参数太多,用了builder模式。

CodeBlock中主要有:

final List formatParts;//保存字面上的值

final List args;//保存替代的值

javapoet源码初识_第2张图片
javapoet源码初识_第3张图片

前面几步骤都是对类的初始化,下面来看看调用了JavaFile的writeTo后实际做了些什么。

javapoet源码初识_第4张图片

JavaPoet两次生成java文件字符串,在第一次中生成字符串用于收集import的类型信息,第二次才输出字符串到文件中。

在JavaPoet中,所有java文件的抽象元素都定义了emit方法,如TypeSepc,ParameterSepc等,emit方法传入CodeWriter对象输出字符串。上层元素调用下层元素的emit方法,如JavaFile的emit方法调用TypeSpec的emit方法,从而实现整个java文件字符串的生成。

所有的java文件抽象元素的emit方法最终都会调用CodeWriter的emit方法,CodeWriter是对字符串输出的抽象。

你可能感兴趣的:(javapoet源码初识)