JavaPoet

转载请注明出处:http://blog.csdn.net/crazy1235/article/details/51876192


JavaPoet

JavaPoet 是一个用来生成 .java源文件的Java API。

当做如注解或者数据库模式、协议格式等事情时,生成源文件就比较有用处。

Example

HelloWorld 类为例:

package com.example.helloworld;

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

上面的代码就是使用javapoet用下面的代码进行生成的:

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

通过MethodSpec类来创建一个”main”方法,并配置了修饰符、返回值类型、参数以及代码语句。然后把这个main方法添加到 HelloWorld 类中,最后添加到 HelloWorld.java文件中。

这个例子中,我们将文件通过Sytem.out 进行输出,但是同样也可以使用(JavaFile.toString()) 得到string字符串,或者通过 (JavaPoet.writeTo()) 方法写入到文件系统中。

Javadoc 中包括了完整的JavaPoet API, 我们接着往下看。

Code & Control Flow

大多数JavaPoet的API使用的是简单的不可变的Java对象。通过建造者模式,链式方法,可变参数是的API比较友好。JavaPoet提供了(TypeSpec)用于创建类或者接口,(FieldSpec)用来创建字段,(MethodSpec)用来创建方法和构造函数,(ParameterSpec)用来创建参数,(AnnotationSpec)用于创建注解。

但是如果没有语句类,没有语法结点数,可以通过字符串来构建代码块:

MethodSpec main = MethodSpec.methodBuilder("main")
    .addCode(""
        + "int total = 0;\n"
        + "for (int i = 0; i < 10; i++) {\n"
        + "  total += i;\n"
        + "}\n")
    .build();

生成的代码如下:

void main() {
  int total = 0;
  for (int i = 0; i < 10; i++) {
    total += i;
  }
}

人为的输入分号、换行和缩进是比较乏味的。所以JavaPoet提供了相关API使它变的容易。

addStatement() 负责分号和换行,beginControlFlow() + endControlFlow() 需要一起使用,提供换行符和缩进。

MethodSpec main = MethodSpec.methodBuilder("main")
    .addStatement("int total = 0")
    .beginControlFlow("for (int i = 0; i < 10; i++)")
    .addStatement("total += i")
    .endControlFlow()
    .build();

这个例子稍微有点差劲。生成的代码如下:

private MethodSpec computeRange(String name, int from, int to, String op) {
  return MethodSpec.methodBuilder(name)
      .returns(int.class)
      .addStatement("int result = 0")
      .beginControlFlow("for (int i = " + from + "; i < " + to + "; i++)")
      .addStatement("result = result " + op + " i")
      .endControlFlow()
      .addStatement("return result")
      .build();
}

调用computeRange("multiply10to20", 10, 20, "*")就生成如下代码:

int multiply10to20() {
  int result = 0;
  for (int i = 10; i < 20; i++) {
    result = result * i;
  }
  return result;
}

方法生成方法!JavaPoet生成的是源代码而不是字节码,所以可以通过阅读源码确保正确。

$L for Literals

字符串连接的方法beginControlFlow()addStatement是分散开的,操作较多。

针对这个问题, JavaPoet 提供了一个语法但是有违String.format()语法. 通过 $L 来接受一个 literal 值。 这有点像 Formatter’s %s:

private MethodSpec computeRange(String name, int from, int to, String op) {
  return MethodSpec.methodBuilder(name)
      .returns(int.class)
      .addStatement("int result = 0")
      .beginControlFlow("for (int i = $L; i < $L; i++)", from, to)
      .addStatement("result = result $L i", op)
      .endControlFlow()
      .addStatement("return result")
      .build();
}

Literals 直接写在输出代码中,没有转义。 它的类型可以是字符串、primitives和一些接下来要说的JavaPoet类型。

$S for Strings

当输出的代码包含字符串的时候, 可以使用 $S 表示一个 string。 下面的代码包含三个方法,每个方法返回自己的名字:

public static void main(String[] args) throws Exception {
  TypeSpec helloWorld = TypeSpec.classBuilder("HelloWorld")
      .addModifiers(Modifier.PUBLIC, Modifier.FINAL)
      .addMethod(whatsMyName("slimShady"))
      .addMethod(whatsMyName("eminem"))
      .addMethod(whatsMyName("marshallMathers"))
      .build();

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

  javaFile.writeTo(System.out);
}

private static MethodSpec whatsMyName(String name) {
  return MethodSpec.methodBuilder(name)
      .returns(String.class)
      .addStatement("return $S", name)
      .build();
}

输出结果如下:

public final class HelloWorld {
  String slimShady() {
    return "slimShady";
  }

  String eminem() {
    return "eminem";
  }

  String marshallMathers() {
    return "marshallMathers";
  }
}

$T for Types

使用Java内置的类型会使代码比较容易理解。JavaPoet极大的支持这些类型,通过 $T 进行映射,会自动import声明。

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

自动完成import声明,生成代码如下:

package com.example.helloworld;

import java.util.Date;

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

再举一个相似的例子,但是应用了一个不存在的类:

ClassName hoverboard = ClassName.get("com.mattel", "Hoverboard");

MethodSpec today = MethodSpec.methodBuilder("tomorrow")
    .returns(hoverboard)
    .addStatement("return new $T()", hoverboard)
    .build();

类不存在,但是代码是完整的:

package com.example.helloworld;

import com.mattel.Hoverboard;

public final class HelloWorld {
  Hoverboard tomorrow() {
    return new Hoverboard();
  }
}

ClassName 这个类非常重要, 当你使用JavaPoet的时候会频繁的使用它。

它可以识别任何声明类。具体看下面的例子:

ClassName hoverboard = ClassName.get("com.mattel", "Hoverboard");
ClassName list = ClassName.get("java.util", "List");
ClassName arrayList = ClassName.get("java.util", "ArrayList");
TypeName listOfHoverboards = ParameterizedTypeName.get(list, hoverboard);

MethodSpec beyond = MethodSpec.methodBuilder("beyond")
    .returns(listOfHoverboards)
    .addStatement("$T result = new $T<>()", listOfHoverboards, arrayList)
    .addStatement("result.add(new $T())", hoverboard)
    .addStatement("result.add(new $T())", hoverboard)
    .addStatement("result.add(new $T())", hoverboard)
    .addStatement("return result")
    .build();

JavaPoet将每一种类型进行分解,并尽可能的导入其声明.

package com.example.helloworld;

import com.mattel.Hoverboard;
import java.util.ArrayList;
import java.util.List;

public final class HelloWorld {
  List<Hoverboard> beyond() {
    List<Hoverboard> result = new ArrayList<>();
    result.add(new Hoverboard());
    result.add(new Hoverboard());
    result.add(new Hoverboard());
    return result;
  }
}

Import static

JavaPoet支持import static。它显示的收集类型成员的名称。例子如下:

...
ClassName namedBoards = ClassName.get("com.mattel", "Hoverboard", "Boards");

MethodSpec beyond = MethodSpec.methodBuilder("beyond")
    .returns(listOfHoverboards)
    .addStatement("$T result = new $T<>()", listOfHoverboards, arrayList)
    .addStatement("result.add($T.createNimbus(2000))", hoverboard)
    .addStatement("result.add($T.createNimbus(\"2001\"))", hoverboard)
    .addStatement("result.add($T.createNimbus($T.THUNDERBOLT))", hoverboard, namedBoards)
    .addStatement("$T.sort(result)", Collections.class)
    .addStatement("return result.isEmpty() $T.emptyList() : result", Collections.class)
    .build();

TypeSpec hello = TypeSpec.classBuilder("HelloWorld")
    .addMethod(beyond)
    .build();

JavaFile.builder("com.example.helloworld", hello)
    .addStaticImport(hoverboard, "createNimbus")
    .addStaticImport(namedBoards, "*")
    .addStaticImport(Collections.class, "*")
    .build();

JavaPoet将会首先添加 import static 代码块进行配置,当然也需要导入其他所需的类型引用。

package com.example.helloworld;

import static com.mattel.Hoverboard.Boards.*;
import static com.mattel.Hoverboard.createNimbus;
import static java.util.Collections.*;

import com.mattel.Hoverboard;
import java.util.ArrayList;
import java.util.List;

class HelloWorld {
  List<Hoverboard> beyond() {
    List<Hoverboard> result = new ArrayList<>();
    result.add(createNimbus(2000));
    result.add(createNimbus("2001"));
    result.add(createNimbus(THUNDERBOLT));
    sort(result);
    return result.isEmpty() ? emptyList() : result;
  }
}

$N for Names

使用 $N 可以引用另外一个通过名字生成的声明。

public String byteToHex(int b) {
  char[] result = new char[2];
  result[0] = hexDigit((b >>> 4) & 0xf);
  result[1] = hexDigit(b & 0xf);
  return new String(result);
}

public char hexDigit(int i) {
  return (char) (i < 10 ? i + ‘0‘ : i - 10 + ‘a‘);
}

生成的代码如下,在byteToHex()方法中通过$N来引用 hexDigit()方法作为一个参数:

MethodSpec hexDigit = MethodSpec.methodBuilder("hexDigit")
    .addParameter(int.class, "i")
    .returns(char.class)
    .addStatement("return (char) (i < 10 ? i + ‘0‘ : i - 10 + ‘a‘)")
    .build();

MethodSpec byteToHex = MethodSpec.methodBuilder("byteToHex")
    .addParameter(int.class, "b")
    .returns(String.class)
    .addStatement("char[] result = new char[2]")
    .addStatement("result[0] = $N((b >>> 4) & 0xf)", hexDigit)
    .addStatement("result[1] = $N(b & 0xf)", hexDigit)
    .addStatement("return new String(result)")
    .build();

Methods

上面的例子中的方法都有方法体。 使用 Modifiers.ABSTRACT 创建的方法是没有方法体的。通常用来创建一个抽象类或接口。

MethodSpec flux = MethodSpec.methodBuilder("flux")
    .addModifiers(Modifier.ABSTRACT, Modifier.PROTECTED)
    .build();

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

生成如下代码:

public abstract class HelloWorld {
  protected abstract void flux();
}

当执行修饰符的时。JavaPoet用的是

javax.lang.model.element.Modifier类,这个类在android平台上不可用. 这只限制与生成代码阶段;输出的代码可运行在任何平台上: JVMs, Android,

and GWT。

方法可能会有参数,异常,可变参数,注释,注解,类型变量和一个返回类型。这些都可以通过 MethodSpec.Builder 来进行配置。

Constructors

MethodSpec 也可以用来创建构造函数:

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;
  }
}

多数情况下,构造方法同普通方法一样。当生成代码时,构造函数会先于其他方法生成。

Parameters

通过 ParameterSpec.builder() 可以创建参数,或者直接调用 MethodSpec类的 addParameter() 方法添加参数:

ParameterSpec android = ParameterSpec.builder(String.class, "android")
    .addModifiers(Modifier.FINAL)
    .build();

MethodSpec welcomeOverlords = MethodSpec.methodBuilder("welcomeOverlords")
    .addParameter(android)
    .addParameter(String.class, "robot", Modifier.FINAL)
    .build();

虽然上面的代码生成androidrobot这两个参数是不同的方式,但是输出是一样的:

void welcomeOverlords(final String android, final String robot) {
}

当参数有注解(比如 @Nullable)的时候,通过扩展的 Builder 方式创建参数是比较方便的。

Fields

字段通参数一样通过 build 方式创建:

FieldSpec android = FieldSpec.builder(String.class, "android")
    .addModifiers(Modifier.PRIVATE, Modifier.FINAL)
    .build();

TypeSpec helloWorld = TypeSpec.classBuilder("HelloWorld")
    .addModifiers(Modifier.PUBLIC)
    .addField(android)
    .addField(String.class, "robot", Modifier.PRIVATE, Modifier.FINAL)
    .build();

生成如下代码:

public class HelloWorld {
  private final String android;

  private final String robot;
}

通关 Builder 方式很容易生成带注释、注解或者初始化的字段。

Field的初始化代码如下:

FieldSpec android = FieldSpec.builder(String.class, "android")
    .addModifiers(Modifier.PRIVATE, Modifier.FINAL)
    .initializer("$S + $L", "Lollipop v.", 5.0d)
    .build();

生成代码:

private final String android = "Lollipop v." + 5.0;

Interfaces

JavaPoet同样可以生成接口。注意接口的方法必须是 PUBLIC

ABSTRACT 类型,接口的变量必须是 PUBLIC STATIC FINAL 类型。

创建接口的时候必须要添加上这些修饰符。

TypeSpec helloWorld = TypeSpec.interfaceBuilder("HelloWorld")
    .addModifiers(Modifier.PUBLIC)
    .addField(FieldSpec.builder(String.class, "ONLY_THING_THAT_IS_CONSTANT")
        .addModifiers(Modifier.PUBLIC, Modifier.STATIC, Modifier.FINAL)
        .initializer("$S", "change")
        .build())
    .addMethod(MethodSpec.methodBuilder("beep")
        .addModifiers(Modifier.PUBLIC, Modifier.ABSTRACT)
        .build())
    .build();

但是这些修饰符在生成的java文件中是找不到的。这些都是缺省值。

public interface HelloWorld {
  String ONLY_THING_THAT_IS_CONSTANT = "change";

  void beep();
}

Enums

通过 enumBuilder 可以创建枚举类型, 调用 addEnumConstant() 可添加枚举变量:

TypeSpec helloWorld = TypeSpec.enumBuilder("Roshambo")
    .addModifiers(Modifier.PUBLIC)
    .addEnumConstant("ROCK")
    .addEnumConstant("SCISSORS")
    .addEnumConstant("PAPER")
    .build();

生成如下代码:

public enum Roshambo {
  ROCK,

  SCISSORS,

  PAPER
}

Fancy enums 也是支持的。

TypeSpec helloWorld = TypeSpec.enumBuilder("Roshambo")
    .addModifiers(Modifier.PUBLIC)
    .addEnumConstant("ROCK", TypeSpec.anonymousClassBuilder("$S", "fist")
        .addMethod(MethodSpec.methodBuilder("toString")
            .addAnnotation(Override.class)
            .addModifiers(Modifier.PUBLIC)
            .addStatement("return $S", "avalanche!")
            .build())
        .build())
    .addEnumConstant("SCISSORS", TypeSpec.anonymousClassBuilder("$S", "peace")
        .build())
    .addEnumConstant("PAPER", TypeSpec.anonymousClassBuilder("$S", "flat")
        .build())
    .addField(String.class, "handsign", Modifier.PRIVATE, Modifier.FINAL)
    .addMethod(MethodSpec.constructorBuilder()
        .addParameter(String.class, "handsign")
        .addStatement("this.$N = $N", "handsign", "handsign")
        .build())
    .build();

生成代码:

public enum Roshambo {
  ROCK("fist") {
    @Override
    public void toString() {
      return "avalanche!";
    }
  },

  SCISSORS("peace"),

  PAPER("flat");

  private final String handsign;

  Roshambo(String handsign) {
    this.handsign = handsign;
  }
}

Anonymous Inner Classes

在上面的枚举代码汇总,使用了 Types.anonymousInnerClass()。匿名内部类也可以在代码块中使用。 通过 $L 引用匿名内部类:

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

生成的代码包含一个类和一个方法:

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

Annotations

对方法添加注解非常简单:

MethodSpec toString = MethodSpec.methodBuilder("toString")
    .addAnnotation(Override.class)
    .returns(String.class)
    .addModifiers(Modifier.PUBLIC)
    .addStatement("return $S", "Hoverboard")
    .build();

生成如下代码:

  @Override
  public String toString() {
    return "Hoverboard";
  }

通过 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);

注解同样可以注解其它的注解。通过 $L 进行引用:

MethodSpec logRecord = MethodSpec.methodBuilder("recordEvent")
    .addModifiers(Modifier.PUBLIC, Modifier.ABSTRACT)
    .addAnnotation(AnnotationSpec.builder(HeaderList.class)
        .addMember("value", "$L", AnnotationSpec.builder(Header.class)
            .addMember("name", "$S", "Accept")
            .addMember("value", "$S", "application/json; charset=utf-8")
            .build())
        .addMember("value", "$L", AnnotationSpec.builder(Header.class)
            .addMember("name", "$S", "User-Agent")
            .addMember("value", "$S", "Square Cash")
            .build())
        .build())
    .addParameter(LogRecord.class, "logRecord")
    .returns(LogReceipt.class)
    .build();

生成如下代码:

@HeaderList({
    @Header(name = "Accept", value = "application/json; charset=utf-8"),
    @Header(name = "User-Agent", value = "Square Cash")
})
LogReceipt recordEvent(LogRecord logRecord);

addMember() 可以调用多次。

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

使用 $T 可以自动导入类型的引用。

Download

下载最新的 the latest .jar

或者添加Maven依赖:

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

或者Gradle依赖:

compile ‘com.squareup:javapoet:1.7.0‘

Snapshots of the development version are available in Sonatype’s snapshots repository.

License

Copyright 2015 Square, Inc.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

   http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

JavaWriter

JavaPoet is the successor to JavaWriter. New projects should prefer JavaPoet because

it has a stronger code model: it understands types and can manage imports automatically. JavaPoet is

also better suited to composition: rather than streaming the contents of a .java file

top-to-bottom in a single pass, a file can be assembled as a tree of declarations.

JavaWriter continues to be available in GitHub and Maven Central.

时间: 2024-08-13 08:42:01

JavaPoet的相关文章

米菲纸尿裤微商发货渠道自定义AutoService、Javapoet讲解

一.上篇文章提到自定义米菲纸尿裤微商发货渠道processor中用到AutoService 文章中我们用到了AutoService, 使用@AutoService(Processor.class),编译后 麦139*261*150*05(微电)META-INF AutoService会自动在META-INF文件夹下生成Processor配置信息文件,该文件里就是实现该服务接口的具体实现类.而当外部程序装配这个模块的时候,就能通过该jar包META-INF/services/里的配置文件找到具体的

Javapoet源码解析

Javapoet:是生成.java源文件的开源API github:https://github.com/square/javapoet 以生成一个HelloWrold.java文件为例: 1 package com.example.helloworld; 2 3 public final class HelloWorld { 4 public static void main(String[] args) { 5 System.out.println("Hello, JavaPoet!&quo

java——JavaPoet

public static void main(String [] args){ ClassName activity = ClassName.get("android.app", "Activity"); TypeSpec.Builder mainActivityBuilder = TypeSpec.classBuilder("MainActivity") .addModifiers(Modifier.PUBLIC) .superclass(a

自定义注解框架的那些事

一.前言 距离上次更新已过一个半月,工作太忙也不是停更的理由.我这方面做得很不好,希望大家给予监督.首先会讲解[编译期资源注入],接着是[下拉刷新注入](通过注解来实现下拉刷新功能),最后打造一款[特色的注解框架]. 大家准备好公交卡了吗,开车了 - 二.什么是注解 每位童鞋对 注解 都有自己的理解,字面上的意思就是[额外的加入],在项目当中使用的注解的框架已经越来越多,如 : retrofit ,butterknife,androidannotations - 2017年Android百大框架

Android 如何编写基于编译时注解的项目

本文已在CSDN<程序员>杂志刊登. 本文已授权微信公众号:鸿洋(hongyangAndroid)在微信公众号平台原创首发. 转载请标明出处: http://blog.csdn.net/lmj623565791/article/details/51931859: 本文出自:[张鸿洋的博客] 一.概述 在Android应用开发中,我们常常为了提升开发效率会选择使用一些基于注解的框架,但是由于反射造成一定运行效率的损耗,所以我们会更青睐于编译时注解的框架,例如: butterknife免去我们编写

你必须知道的APT、annotationProcessor、android-apt、Provided、自定义注解

你可能经常在build.gradle文件中看到,这样的字眼,annotationProcessor.android-apt.Provided,它们到底有什么作用?下面就一起来看看吧 1.什么是APT? 随着一些如ButterKnife,dagger等的开源注解框架的流行,APT的概念也越来越被熟知. annotationProcessor和android-apt的功能是一样的,它们是替代关系,在认识它们之前,先来看看APT. APT(Annotation Processing Tool)是一种处

Android 编译时注解-提升

Android 编译时注解-提升 背景 在前面的文章中,讲解了注解和编译时注解等一些列相关的内容,为了更加全面和真是的了解Android 编译时注解在实战项目中的使用,本文采取实现主流框架butterknife注入view去全面认识编译时注解. 注解专栏-博客 效果 先来张图压压惊,实现效果butterknife的view绑定 使用 仿照butterknife实现了@BindView注解,通过WzgJector.bind方法绑定当前MainActivity,整体和butterknife使用完全一

一小时搞明白注解处理器(Annotation Processor Tool)

Java中的注解是个很神奇的东西,还不了解的可以看下一小时搞明白自定义注解(Annotation).现在很多Android的库都用使用注解实现的,比如ButterKnife,我们不防也来学习一下,学完注解处理器,我们尝试写一个简单的类似ButterKnife的东西来绑定控件. 什么是注解处理器? 注解处理器是(Annotation Processor)是javac的一个工具,用来在编译时扫描和编译和处理注解(Annotation).你可以自己定义注解和注解处理器去搞一些事情.一个注解处理器它以J

Android注解使用之通过annotationProcessor注解生成代码实现自己的ButterKnife框架

前言: Annotation注解在Android的开发中的使用越来越普遍,例如EventBus.ButterKnife.Dagger2等,之前使用注解的时候需要利用反射机制势必影响到运行效率及性能,直到后来android-apt的出现通过注解根据反射机制动态编译生成代码的方式来解决在运行时不再使用发射机制,不过随着android-apt的退出不再维护,我们今天利用Android studio的官方插件annotationProcessor来实现一下自己的ButterKnife UI注解框架. 需