JavaPoet - 优雅地生成代码

JavaPoet是square的开源框架,用于优雅地生成Java代码。它提供了API来创建.java文件,简化了根据注解、数据库模式、协议生成代码的过程。通过JavaFile、TypeSpec、MethodSpec和FieldSpec等类,JavaPoet实现了代码的层次化构造。项目结构简单,主要类都在com.squareup.javapoet包下。通过注解处理器,可以在编译时动态生成代码,例如在butterknife和Dagger中就应用了JavaPoet。
摘要由CSDN通过智能技术生成

JavaPoet - 优雅地生成代码


一、项目简介

JavaPoet是square推出的开源java代码生成框架,提供Java Api生成.java源文件。这个框架功能非常有用,我们可以很方便的使用它根据注解、数据库模式、协议格式等来对应生成代码。通过这种自动化生成代码的方式,可以让我们用更加简洁优雅的方式要替代繁琐冗杂的重复工作。

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

二、项目总览

该项目代码量相对较小,只有一个package(com.squareup.javapoet),所有类均位于该package下。

2.1 大体结构图

JavaFile.png

2.2 关键类说明

class 说明
JavaFile A Java file containing a single top level class 用于构造输出包含一个顶级类的Java文件
TypeSpec A generated class, interface, or enum declaration 生成类,接口,或者枚举
MethodSpec A generated constructor or method declaration 生成构造函数或方法
FieldSpec A generated field declaration 生成成员变量或字段
ParameterSpec A generated parameter declaration 用来创建参数
AnnotationSpec A generated annotation on a declaration 用来创建注解

在JavaPoet中,JavaFile是对.java文件的抽象,TypeSpec是类/接口/枚举的抽象,MethodSpec是方法/构造函数的抽象,FieldSpec是成员变量/字段的抽象。这几个类各司其职,但都有共同的特点,提供内部Builder供外部更多更好地进行一些参数的设置以便有层次的扩展性的构造对应的内容。

另外,它提供$L(for Literals), $S(for Strings), $T(for Types), $N(for Names)等标识符,用于占位替换。

三、相关使用

3.1 API使用

关于JavaPoet 的API使用,官方Github主页已经有很详细的使用说明和示例了,具体可前往查看。此处不赘述,详见 项目主页、源码及使用说明

3.2 一个简单示例

下面就让我们以一个简单HelloWorld的例子来开启我们的JavaPoet之旅。

引入库:
build.gradle

compile 'com.squareup:javapoet:1.9.0'

例子如下:

package com.example.helloworld;

public final class HelloWorld {
   
  public static void main(String[] args) {
    System.out.println("Hello, JavaPoet!");
  }
}

上方的代码是通过下方代码调用JavaPoet的API生成的:

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

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

javaFile.writeTo(System.out);

四、源码浅析

下面来看看调用了JavaFile的writeTo后实际做了些什么。

  public void writeTo(Appendable out) throws IOException {
    // First pass: emit the entire class, just to collect the types we'll need to import.
    CodeWriter importsCollector = new CodeWriter(NULL_APPENDABLE, indent, staticImports);
    emit(importsCollector);
    Map<String, ClassName> suggestedImports = importsCollector.suggestedImports();

    // Second pass: write the code, taking advantage of the imports.
    CodeWriter codeWriter = new CodeWriter(out, indent, suggestedImports, staticImports);
    emit(codeWriter);
  }

通过源码可以知道,writeTo分为两部分:第一步收集import,记录下来后第二步才跟随内容一起写到CodeWriter。

另外我们可以看到源码中的emit方法,通过查看其它源码发现,在JavaPoet中,所有java文件的抽象元素都定义了emit方法,如TypeSepc,ParameterSepc等,emit方法传入CodeWriter对象输出字符串。上层元素调用下层元素的emit方法,如JavaFile的emit方法调用TypeSpec的emit方法,从而实现整个java文件字符串的生成。

下面我们以MethodSpec为例,查看其emit代码:


  void emit(CodeWriter codeWriter, String enclosingName, Set<Modifier> implicitModifiers)
      throws IOException {
    codeWriter.emitJavadoc(javadoc);
    codeWriter.emitAnno
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值