title | date | author | tags | keywords | categories | reward | reward_title | reward_wechat | reward_alipay | source_url | translator | translator_url |
---|---|---|---|---|---|---|---|---|---|---|---|---|
[译]Better Annotation Processing: Supporting Stubs in kapt |
2015-06-22 08:28:00 -0700 |
Andrey Breslav |
官方动态 |
false |
Have a nice Kotlin! |
我们宣布 kapt 之前,Kotlin 的注释处理工具,并讨论了其局限性。现在,大部分**限制正在消失,可以使用
0.1-SNAPSHOT预览版本的
kapt`更新版本。<span id =“ more-2385“>
通过截取注解处理器(例如 Dagger 2)和javac
之间的通信,初始版本的kapt
工作,并在 Java 类之上添加了已经编译的 Kotlin 类,代码> javac`在源中看到自己。这种方法的问题是,由于 Kotlin 类必须已经被编译,所以没有办法引用处理器生成的任何代码(例如 Dagger 的模块类)。因此,我们必须在 Java 中编写 Dagger 应用程序类。
如 在上一篇博文中讨论过 可以通过在运行javac
之前生成 Kotlin 类的**来克服该问题,然后在javac
完成后运行真正的编译。存根只包含声明,没有方法体。 Kotlin 编译器用于在内存中创建这样的存根(它们用于 Java 互操作,当 Java 代码回溯到 Kotlin 时),所以我们只需要将它们序列化到磁盘上的文件。
Stubs 支持依赖于注释处理器生成的代码的框架。例如,您现在可以使用 DBFlow 在 Kotlin:
{% raw %}
{% endraw %}public object ItemRepository {
public fun getAll(): MutableList<Item> {
return Select()
.from(javaClass<Item>())
.where()
.orderBy(false, Item_Table.UPDATED_AT)
.queryList()
}
}
{% raw %}
{% endraw %}由 DBFLow 库提供类似 DSL 的功能Select()
,()等,DBFlow 的注释处理器生成
Item_Table,上面的 Kotlin 代码可以高兴地参考它! 完整的例子是可用的 [这里](https://github.com/yanex/kotlin-poc) (谢谢 [Mickele Moriconi](https://github.com/mickele) 对于初始代码)。 请注意,生成存根需要相对较多的工作,因为所有声明必须解决,有时候知道返回类型需要分析表达式(函数或属性初始化程序的主体在
=符号之后)。因此,在
kapt`中使用存根减慢了你的构建。这就是为什么存根默认情况下关闭,为了使它们能够在您的 build.gradle 文件 :
{% raw %}
{% endraw %}kapt {
generateStubs = true
}
{% raw %}
{% endraw %}此外,kapt
现在可以处理传递参数到注释处理器。这是一个例子 AndroidAnnotations 图书馆:
{% raw %}
{% endraw %}kapt {
generateStubs = true
arguments {
arg("androidManifestFile", variant.outputs[0].processResourcesTask.manifestFile)
}
}
{% raw %}
{% endraw %}正如您可能已经注意到的那样,我们生成二进制代码.class
-files,而不是作为.java
源。这更加方便,原因有很多:
- 我们已经为不同的目的生成了必要的字节,
- 在一个类文件中,我们可以简单地跳过一个方法的主体,不需要生成一个将使 javac 快乐的存根体,
- javac 将编译存根源并生成稍后需要删除的类文件,
- 这种方式,旧的(快速)和新(较慢)的 kapt 模式使用相同的基本机制。
但是二进制存根有自己的缺点:
- 如果注释由 @Retention(RetentionPolicy.SOURCE)标记,则它不在二进制文件中,
- javac 不会在类层次结构下传播 @Inherited 注释。
到目前为止,我们还没有解决后一个问题,但前者的源保留注释是绝对关键的,因为许多流行的框架(如 DBFlow )他们的注释源保留。幸运的是,当javac
读取二进制文件时,它不会仔细检查注释,如果我们将类保留的注释写入类文件,尽管声明了保留,它会高兴地看到它。这是我们现在所做的<img alt =“:)”class =“wp-smiley”data-recalc-dims =“1”src =“https://i2.wp.com/blog.jetbrains.com/kotlin /wp-includes/images/smilies/simple-smile.png?w=640&ssl=1“style =”height:1em; max-height:1em“
在kapt
上还有一些工作尚待处理。
注释处理本身最大的问题是支持 @ 继承注释 。我们需要解决javac
,不会将它们传播到二进制类的层次结构中。
但是真正的问题在于外部的kapt
:许多框架,如 AndroidAnnotation 并且上述 DBFlow 想要直接将值注入到字段中,而 Kotlin 则是关于安全的,并且使这些字段private
正在阻碍。这就是为什么现在我们必须在 Java 中编写 DBFlow“表类” Item.java 在我们的例子中
所以,我们正在考虑一个选择性功能,使得 Kotlin 生成的类中的非私有字段。
新的kapt
尚未发布,但欢迎您尝试并告诉我们您的想法。以下是您如何做的例子:
{% raw %}
{% endraw %}repositories {
maven { url 'https://raw.github.com/Raizlabs/maven-releases/master/releases' }
maven { url 'http://oss.sonatype.org/content/repositories/snapshots' }
jcenter()
}
dependencies {
...
// DBFlow
kapt 'com.raizlabs.android:DBFlow-Compiler:2.0.0'
compile 'com.raizlabs.android:DBFlow-Core:2.0.0'
compile 'com.raizlabs.android:DBFlow:2.0.0'
// Kotlin
compile 'org.jetbrains.kotlin:kotlin-stdlib:0.1-SNAPSHOT'
}
kapt {
generateStubs = true
}
{% raw %}
{% endraw %}再次参见完整的 DBFlow 示例 这里 。 请告诉我们:
- 有什么对你有用
- 什么没有?
- 你喜欢还是不喜欢什么?
- 任何我们忽视的用例?
谢谢!