Android關於AutoService、Javapoet講解

1、上篇文章提到自定義processor中用到AutoService

文章中咱們用到了AutoService, 使用@AutoService(Processor.class),編譯後java

 

AutoService會自動在META-INF文件夾下生成Processor配置信息文件,該文件裏就是實現該服務接口的具體實現類。而當外部程序裝配這個模塊的時候,
就能經過該jar包META-INF/services/裏的配置文件找到具體的實現類名,並裝載實例化,完成模塊的注入。
基於這樣一個約定就能很好的找到服務接口的實現類,而不須要再代碼裏制定,方便快捷。應用依賴以下:

compile 'com.google.auto.service:auto-service:1.0-rc2'

  

2、javapoet經常使用api

JavaPoet是square推出的開源java代碼生成框架,提供Java Api生成.java源文件。這個框架功能很是有用,咱們能夠很方便的使用它根據註解、數據庫模式、協議格式等來對應生成代碼。經過這種自動化生成代碼的方式,可讓咱們用更加簡潔優雅的方式要替代繁瑣冗雜的重複工做。引用依賴:android

compile 'com.squareup:javapoet:1.7.0'

 

該項目結構以下:程序員

 

相關類介紹數據庫

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供外部更多更好地進行一些參數的設置以便有層次的擴展性的構造對應的內容api

 

經常使用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)) 
    會給生成的類加上泛型

佔位符less

  • $L表明的是字面量
  • $S for Strings
  • $N for Names(咱們本身生成的方法名或者變量名等等)
  • $T for Types

 

3、javapoet的使用

package com.example.helloworld;

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

  

上面的代碼咱們能夠調用javapoet的api方法去生成:ide

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);//能夠看出,addModifiers對方法的修飾約束,addParameter添加方法參數 ,addStatement方法體,returns返回值,最後寫入java文件中

  

代碼和控制流程
大多數JavaPoet的API使用普通的舊的不可變的Java對象。也有建設者,方法鏈和可變參數使API友好。JavaPoet爲類和接口(),fields(),方法和構造函數(),參數()和註釋()提供模型。

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

  

咱們能夠子自定義方法去調用ui

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, "*") 生成下面的java代碼

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

  

對於$T泛型 ,咱們的Java程序員喜歡咱們的類型:他們讓咱們的代碼更容易理解。JavaPoet在船上。它具備豐富的內置支持類型,包括自動生成import 語句。只是$T用來引用類型:

package com.example.helloworld;

import java.util.Date;

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

  

要生成上面代碼 能夠用下面的javapoet去實現

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

  

JavaPoet支持import static它經過明確收集類型成員名稱來完成。見下面代碼:

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

  

若是咱們想生成構造Constructors,也很簡單:

public class HelloWorld {
  private final String greeting;

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

  

要實現上面java代碼,用javapoet去實現,以下:

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

  

還可定義枚舉類

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


public enum Roshambo {
  ROCK,

  SCISSORS,

  PAPER
}

  

還有匿名內部類的實現

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();
This generates a method that contains a class that contains a method:

void sortByLength(List<String> strings) {
  Collections.sort(strings, new Comparator<String>() {
    @Override
    public int compare(String a, String b) {
      return a.length() - b.length();
    }
  });
}

  

也可建立註解:

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

  

建立註釋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);

  

用法不少,還能夠用FieldSpec.builder建立屬性變量,ParameterSpec建立方法參數

 

4、總結 問題

若是咱們在自定義processor的時候找不到javax.annotation.processing.*包下的類,則建立java module 而非android module

相關文章
相關標籤/搜索