前言

最近在用Dagger开发应用,Dagger是google在square的基础上去反射的依赖注入框架。

Dagger会根据定义的注解在编译阶段根据依赖注入的配置生成相应的代码,来减少运行期间反射的开销。

Dagger依赖了JavaPoet和JavaFormat来辅助实现生成代码,这里主要介绍下JavaPoet的内容和使用。

JavaPoet

JavaPoet这样定义自己的项目。

Use beautiful Java code to generate beautiful Java code

所以JavaPoet定义了一系列类来尽可能优雅的描述java源文件的结构。观察JavaPoet的代码主要的类可以分为以下几种:

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

    • AnnotationSpec
    • FieldSpec
    • MethodSpec
    • ParameterSpec
    • TypeSpec
  • Name 用来描述类型的引用,包括Void,原始类型(int,long等)和Java类等。
    • TypeName
    • ArrayTypeName
    • ClassName
    • ParameterizedTypeName
    • TypeVariableName
    • WildcardTypeName
  • CodeBlock 用来描述代码块的内容,包括普通的赋值,if判断,循环判断等。
  • JavaFile 完整的Java文件,JavaPoet的主要的入口。
  • CodeWriter 读取JavaFile并转换成可阅读可编译的Java源文件。

示例

下面通过一个例子来完整的实现一个Java类的定义。

通过下面的maven依赖可以引用JavaPoet包。

    <dependency>
<groupId>com.squareup</groupId>
<artifactId>javapoet</artifactId>
<version>1.7.0</version>
</dependency>

完整的代码放在Github。这里介绍一下主要的方法。

  1. AnnotationSpec 添加MyAnnotation的注解,然后设置属性hello=world
    private static AnnotationSpec makeAnnotationSpec() {
AnnotationSpec.Builder builder = AnnotationSpec.builder(ClassName.get("org.wcong.test.poet", "MyAnnotation"));
CodeBlock.Builder codeBlockBuilder = CodeBlock.builder().add("$S", "world");
builder.addMember("hello", codeBlockBuilder.build());
return builder.build();
}
  1. FieldSpec 创建hello的字段并初始化为“world”。
    private static FieldSpec makeFieldSpec() {
FieldSpec.Builder fileSpecBuilder = FieldSpec.builder(String.class, "hello", Modifier.PRIVATE);
fileSpecBuilder.initializer(CodeBlock.of("\"world\""));
return fileSpecBuilder.build();
}
  1. MethodSpec 创建getHello,setHello,toString方法。

    toString使用了ControlFlow判断了hello不等于null,返回"hello world",等于null的时候返回空。
    private static MethodSpec makeToStringMethod() {
MethodSpec.Builder toStringBuilder = MethodSpec.methodBuilder("toString");
toStringBuilder.addModifiers(Modifier.PUBLIC);
toStringBuilder.returns(TypeName.get(String.class));
CodeBlock.Builder toStringCodeBuilder = CodeBlock.builder();
toStringCodeBuilder.beginControlFlow("if( hello != null )");
toStringCodeBuilder.add(CodeBlock.of("return \"hello \"+hello;\n"));
toStringCodeBuilder.nextControlFlow("else");
toStringCodeBuilder.add(CodeBlock.of("return \"\";\n"));
toStringCodeBuilder.endControlFlow();
toStringBuilder.addCode(toStringCodeBuilder.build());
return toStringBuilder.build();
}
private static MethodSpec makeSetMethod() {
MethodSpec.Builder setMethodSpecBuilder = MethodSpec.methodBuilder("setHello");
setMethodSpecBuilder.addModifiers(Modifier.PUBLIC);
setMethodSpecBuilder.returns(TypeName.VOID);
ParameterSpec.Builder parameterBuilder = ParameterSpec.builder(TypeName.get(String.class), "hello");
setMethodSpecBuilder.addParameter(parameterBuilder.build());
setMethodSpecBuilder.addCode(CodeBlock.builder().add("this.hello = hello;\n").build());
return setMethodSpecBuilder.build();
}
private static MethodSpec makeGetMethod() {
MethodSpec.Builder getMethodSpecBuilder = MethodSpec.methodBuilder("getHello");
getMethodSpecBuilder.addModifiers(Modifier.PUBLIC);
getMethodSpecBuilder.returns(TypeName.get(String.class));
getMethodSpecBuilder.addCode(CodeBlock.builder().add("return hello;\n").build());
return getMethodSpecBuilder.build();
}
  1. JavaFile JavaPoet的主入口,用来描述Java源文件。
    public static void main(String[] args) {
TypeSpec.Builder typeSpecBuilder = TypeSpec.classBuilder("JavaFile");
typeSpecBuilder.addAnnotation(makeAnnotationSpec());
typeSpecBuilder.addField(makeFieldSpec());
typeSpecBuilder.addMethods(makeMethodSpec());
JavaFile.Builder javaFileBuilder = JavaFile.builder("org.wcong.test.poet", typeSpecBuilder.build());
System.out.println(javaFileBuilder.build().toString());
}

运行后输出下面的信息,就是一个完整的类文件了

package org.wcong.test.poet;

import java.lang.String;

@MyAnnotation(
hello = "world"
)
class JavaFile {
private String hello = "world"; public String getHello() {
return hello;
} public void setHello(String hello) {
this.hello = hello;
} public String toString() {
if( hello != null ) {
return "hello "+hello;
} else {
return "";
}
}
}

结语

dagger使用JavaPoet来保存自动生成的类的信息,并通过JavaFormat来格式化生成的Java源文件。后面会介绍关于JavaFormat的内容。

深入Dagger:JavaPoet的使用的更多相关文章

  1. 深入Dagger:自定义AutoValue

    前言 上一篇文章介绍了JavaPoet的原理和使用,这里在介绍一下AutoValue的原理,并模仿自定义实现一个AutoValue. AutoValue的是Google为了实现ValueClass设计 ...

  2. [Android]使用Dagger 2来构建UserScope(翻译)

    以下内容为原创,欢迎转载,转载请注明 来自天天博客:http://www.cnblogs.com/tiantianbyconan/p/6237731.html 使用Dagger 2来构建UserSco ...

  3. [Android]使用Dagger 2进行依赖注入 - Producers(翻译)

    以下内容为原创,欢迎转载,转载请注明 来自天天博客:http://www.cnblogs.com/tiantianbyconan/p/6234811.html 使用Dagger 2进行依赖注入 - P ...

  4. [Android]在Dagger 2中使用RxJava来进行异步注入(翻译)

    以下内容为原创,欢迎转载,转载请注明 来自天天博客: # 在Dagger 2中使用RxJava来进行异步注入 > 原文: 几星期前我写了一篇关于在Dagger 2中使用*Producers*进行 ...

  5. [Android]使用Dagger 2依赖注入 - DI介绍(翻译)

    以下内容为原创,欢迎转载,转载请注明 来自天天博客:http://www.cnblogs.com/tiantianbyconan/p/5092083.html 使用Dagger 2依赖注入 - DI介 ...

  6. [Android]使用Dagger 2依赖注入 - API(翻译)

    以下内容为原创,欢迎转载,转载请注明 来自天天博客:http://www.cnblogs.com/tiantianbyconan/p/5092525.html 使用Dagger 2依赖注入 - API ...

  7. [Android]使用Dagger 2依赖注入 - 自定义Scope(翻译)

    以下内容为原创,欢迎转载,转载请注明 来自天天博客:http://www.cnblogs.com/tiantianbyconan/p/5095426.html 使用Dagger 2依赖注入 - 自定义 ...

  8. [Android]使用Dagger 2依赖注入 - 图表创建的性能(翻译)

    以下内容为原创,欢迎转载,转载请注明 来自天天博客:http://www.cnblogs.com/tiantianbyconan/p/5098943.html 使用Dagger 2依赖注入 - 图表创 ...

  9. [Android]依赖注入框架google的dagger

    分享一下Android依赖注入框架--Google升级版Dagger2框架 Google的Dagger2是对上一版squareup的Dagger改版,话不多说直接上项目代码. Dagger2源码 Da ...

随机推荐

  1. DB2临时表空间的作用

    临时表空间分为系统临时表空间和用户临时表空间 系统临时表空间用来存储各种数据操作(排序.重组表.创建索引.连接表)中所需的内部临时数据,虽然可以创建任意多个系统临时表空间,但建议用户只使用大多数表所使 ...

  2. js确认末尾字符算法挑战

    检查一个字符串(str)是否以指定的字符串(target)结尾. 如果是,返回true;如果不是,返回false. 这个挑战可以通过在ES2015中引入的.endsWith()方法来解决.但是出于这个 ...

  3. 【记录】Mybatis-Generator 数据层代码生成器,自动生成dao类,mapper,pojo类

    Mybatis-Generator 工具来帮我们自动创建pojo类.mapper文件以及dao类并且会帮我们配置好它们的依赖关系. 官方文档地址:http://mybatis.org/generato ...

  4. thinkphp5 自动注册Hook机制钩子扩展

    Hook.php 文件已更新1.修复在linux环境下类的 \ 在basename 下无法获取到类名的问题2.修复linux 环境下无法使用hook::call 调用失败问题 请先安装thinkphp ...

  5. Shell02---变量

    Shell02---变量 1. shell变量概述 1. 什么是变量 变量是Shell传递数据的一种方法,简单理解:用一个固定的字符串去表示不固定的内容,便于后续引用. 2.变量命令规范 变量定义时名 ...

  6. Vue-cli使用prerender-spa-plugin插件预渲染和配置cdn

    参考:https://www.jianshu.com/p/6a4c0b281e7f 使用vue-cli打包项目一般为spa项目,众所周知单页面应用不利于SEO,有ssr和预渲染两种解决方案,这里我们只 ...

  7. linux修改Jvm内存限制

    一.直接通过java 命令去执行class文件的时候,也可以设置JVM参数,eg : java -Xms512m -Xmx1024m HelloWorld在cmd中设置,也必须是执行java命令时 堆 ...

  8. 【leetcode】316. Remove Duplicate Letters

    题目如下: Given a string which contains only lowercase letters, remove duplicate letters so that every l ...

  9. table 中 当前行变量的获取

  10. shell变量,字符串,数组

    一.shell变量定义: 命名只能使用英文字母,数字和下划线,首个字符不能以数字开头: 中间不能有空格,可以使用下划线: 不能使用标点符号: 不能使用bash里的关键字. 变量使用: 使用一个定义过的 ...