如何让注解处理器支持 Kotlin?

友情提醒:如果没搞过注解处理器,这篇文章你看起来可能会比较迷。。

什么是注解处理器

话说,最近尝试了一下写了个注解处理器,也就是我们常见的 apt,在 Kotlin 当中有个插件叫 kapt,说的就是注解处理器。注解处理器能干什么呢?能帮我们生成一些代码,让我们变懒,让我们的代码变优雅(也许吧)。

需要注意的是,这个注解处理器是 Java 编译器的特性,而 Java 编译器根本不知道 Kotlin 是神马东西,于是乎,如果大家在 Android 当中用到了 kapt 这个插件,你就会发现在 build/tmp/kapt3 下面有个 stubs 目录:

这个目录里面会有从你的 Kotlin 源码生成的 Java 源码,注解处理器后面会跟据这些源码去做注解处理,这实际上就是 kapt 的原理啦,如果你之前看到过官方写的介绍 kapt 原理的文章,里面说的 stubs ,就是这个。

话说到这儿,不得不提一句,既然注解处理器是 Java 编译器的特性,于是乎,kotlinjs/kotlin native 是没有这一项功能的。

为什么 AutoService 不认识 Kotlin 写的 Processor?

我们写注解处理器,需要编写一个配置文件让编译器知道哪个是注解处理器的入口:

大家看到图中这个文件是红色的,在 IntelliJ 当中红色的目录都是编译生成的,所以这个文件对于偷懒的人来说也根本不会去手写它,而是用 。

当然,这个需要引入依赖的:

其实这货呢,也是一个注解处理器,帮我们在编译的时候生成注解处理器相应的配置文件。

需要注意的是,如果你的注解处理器入口代码是用 Kotlin 写的,那么 就傻了。

为什么呢?显然直接通过上面的这种依赖方式,只会让 Javac 知道有这么个注解处理器,而 Javac 哪里知道还有什么叫 Kotlin 的东西啊,所以我们还得让 kapt 知道才行。

首先我们要添加 Kotlin 的各种插件,然后在依赖当中用 kapt 引入google 的 ,又由于 中的注解依赖也在这个包里,所以我们还是要把它添加到运行时依赖的(kapt 下面 implementation 那句)。

有了上面的配置,那么我们首先就会在前面提到的 build/tmp/kapt3/stubs 目录中找到我们用 Kotlin 编写的代码转成的 Java 代码,其次 生成的注解处理器的配置也会跑到 kapt3/classes 中(原来是在 build/classes/java/main 中)

如何在注解处理器内识别 Kotlin 代码

既然都是 Java 文件,那么我怎么在注解处理器内识别出来哪些代码是 Java 的,哪些是 Kotlin 的呢?其实这个也不难,对比一下就知道了,给大家看一个例子,我有一个 Kotlin 写的类:

生成的 stub 长这样:

哈哈,一眼就看出来,那个注解,什么鬼,Java 源码肯定不会有的。所以要识别你所处理的类是不是 Kotlin 编写的,只需要:

一旦能够识别出来注解标注的类是 Kotlin,那么我们就可以采用一些 Kotlin Style 的方式生成代码,例如本来如果是 Java 源码,我会生成这样的一个方法:

如果我处理的是 Kotlin 源码,我完全可以生成一个扩展方法让 Kotlin 开发者更愉快地调用:

当然,这个扩展方法也是可以被 Java 开发者很愉快地调用的。

注意 Kotlin 的类型

我们一再提到注解处理器只认识 Java,所以就算你用 Kotlin 定义了一个方法如下:

如果我们用注解处理器处理它的时候,参数 的类型就会变成 Java 的 或者 ,而参数 的类型则会变成 ,注意不是 。

如果你要根据这些类型对应地去生成代码,你需要将这些类型做映射,例如:

这个要怎么办呢?不能怎么办,连 J 神的 Kotlin Poet 都没有做这件事儿,如果我们需要写注解处理器生成 Kotlin 的代码,这一点你需要自己来处理。不过呢,我可以给大家一点儿提示,实际上这个类型转换 Kotlin 编译器是做了的,具体可以参考编译器源码:

这个 当中就存放了需要映射的类型。

怎么生成 Kotlin 源码?

其实我们前面提到了,用 J 神的 Kotlin Poet 这个项目生成 Kotlin 源码的体验几乎与 Java Poet 没差。不过呢,这个项目目前还只是发到了 0.6,所以难免有个小 bug 啥的,例如我要生成一个匿名内部类,就算我只实现了一个接口,它也会给我添加一个构造方法调用的括号:

这样是不对滴。不过这个问题呢,显然也不是什么大问题,已经有大神给了 fix:

Correcting handling of super-classes/interfaces on anonymous classes

https://github.com/square/kotlinpoet/pull/316

由于这个库目前还不算太成熟,参考资料不多,所以如果你想要用,最好去参考一下其中的 test case 来了解其用法。

小结

简单来说,为 Kotlin 提供 apt 服务,无论从编译器(kapt)还是从注解处理器的开发者来讲,你必须都得装作你写的和用的都是 Java 才行。

  • 发表于:
  • 原文链接:http://kuaibao.qq.com/s/20180205A0GE3K00?refer=cp_1026
  • 腾讯「云+社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。

扫码关注云+社区

领取腾讯云代金券