自定义AnnotationProcessor (三)

其实接下来要做的事情就比较简单了

  1. 生成所需要的代码
  2. 写入到一个文件当中
  3. app 项目中就可以直接使用这个类

生成代码使用 square 公司的 kotlinpoet (点这里了解)

注意这里生成的是一个String 字符串,我们需要把它写入到kotlin文件里边

这里用到了之前提到过的Filer ,没看过的可以到上一篇中了解一下

我们使用Filer 的 createResource 方法来创建一个kotlin 文件,并且将上面生成的代码写进去。


开始撸代码

  1. 在 compiler module 中新建一个类,用来做上面这些事情

    1
    2
    3
    4
    5
    6
    class RheaHttpGenerator(val filer: Filer) {
    var element: TypeElement by Delegates.notNull<TypeElement>()
    fun generate() {
    //todo generate file and output
    }
    }
  2. RheaHttpProcessorprocess方法中添加代码

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    override fun process(annotations: Set<TypeElement>, roundEnv: RoundEnvironment): Boolean {
    val set = roundEnv
    .getElementsAnnotatedWith(RheaHttp::class.java)
    val generate = RheaHttpGenerator(filer)
    set.forEach {
    if (it is TypeElement) {
    generate.element = it
    generate.generate()
    }
    }
    return true
    }
  3. 接下来咱们主要了解一下RheaHttpGeneratorgenerate要做的事情

    1. 获取使用注解的类的一些信息

      1
      2
      3
      4
      val qualifiedName = element.qualifiedName.toString()
      val rheaHttp = element.getAnnotation(RheaHttp::class.java)
      val packageName = qualifiedName.substringBeforeLast(".")
      val newClassName = rheaHttp.name

    2. 使用kotlinpoet生成所需要的代码

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      val fileBuilder = KotlinFile.builder(packageName, newClassName)
      val classBuilder = TypeSpec.objectBuilder(newClassName)
      element.enclosedElements.forEach {
      if (it is ExecutableElement) {
      val client = it.getAnnotation(RheaClient::class.java)
      classBuilder.addFun(FunSpec.builder(it.simpleName.toString())
      .addCode(CodeBlock.Builder()
      .addStatement("val client = %T.Builder().build()", OkHttpClient::class)
      .addStatement("val retrofit = %T.Builder()", Retrofit::class)
      .addBuilderStatement(".client(client)")
      .addBuilderStatement(".baseUrl(%S)", client.url)
      .addBuilderStatement(".addConverterFactory(%T())", StringConverterFactory::class)
      .addBuilderStatement(".addConverterFactory(%T.create())", GsonConverterFactory::class)
      .addBuilderStatement(".addCallAdapterFactory(%T.create())", RxJava2CallAdapterFactory::class)
      .addBuilderStatement(".build()")
      .addStatement("return retrofit")
      .build())
      .returns(Retrofit::class)
      .build())
      }
      }
      fileBuilder.addType(classBuilder.build())
      fileBuilder.skipJavaLangImports(true)
      val kotlinFile = fileBuilder.build()
      try {
      kotlinFile.writeTo(filer, packageName, newClassName)
      } catch (e: Exception) {
      e.printStackTrace()
      }
      • element.enclosedElements用于获取封装它直接声明的字段、方法、构造方法和成员类型的注解

完整项目地址:https://github.com/xabad/Rheahttp