title | date | author | tags | keywords | categories | reward | reward_title | reward_wechat | reward_alipay | source_url |
---|---|---|---|---|---|---|---|---|---|---|
[译]Better Annotation Processing: Supporting Stubs in kapt |
2015-06-22 08:28:00 -0700 |
Andrey Breslav |
官方动态 |
false |
Have a nice Kotlin! |
我们宣布 kapt 之前,Kotlin的注释处理工具,并讨论了其局限性。现在,大部分限制正在消失,</ code>可以使用 0.1-SNAPSHOT </ code>预览版本的
kapt </ code>更新版本。<span id =“ more-2385“> </ span>
通过截取注解处理器(例如Dagger 2)和 javac </ code>之间的通信,初始版本的 kapt </ code>工作,并在Java类之上添加了已经编译的Kotlin类,代码> javac </ code>在源中看到自己。这种方法的问题是,由于Kotlin类必须已经被编译,所以没有办法引用处理器生成的任何代码(例如Dagger的模块类)。因此,我们必须在Java中编写Dagger应用程序类。
如 在上一篇博文中讨论过 可以通过在运行 javac </ code>之前生成Kotlin类的</ em> </ em>来克服该问题,然后在 javac </ code>完成后运行真正的编译。存根只包含声明,没有方法体。 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()</ code>,()</ code>等,DBFlow的注释处理器生成 Item_Table </ code>,上面的Kotlin代码可以高兴地参考它!
完整的例子是可用的 这里 (谢谢 Mickele Moriconi 对于初始代码)。
请注意,生成存根需要相对较多的工作,因为所有声明必须解决,有时候知道返回类型需要分析表达式(函数或属性初始化程序的主体在 = </ code>符号之后)。因此,在 kapt </ code>中使用存根减慢了你的构建。这就是为什么存根默认情况下关闭</ strong>,为了使它们能够在您的 build.gradle文件 :
{% raw %}
{% endraw %}
kapt {
generateStubs = true
}
{% raw %}
{% endraw %}
此外, kapt </ code>现在可以处理传递参数到注释处理器。这是一个例子 AndroidAnnotations 图书馆:
{% raw %}
{% endraw %}
kapt {
generateStubs = true
arguments {
arg("androidManifestFile", variant.outputs[0].processResourcesTask.manifestFile)
}
}
{% raw %}
{% endraw %}
正如您可能已经注意到的那样,我们生成二进制代码 .class </ code> -files,而不是作为 .java </ code>源。这更加方便,原因有很多:
- 我们已经为不同的目的生成了必要的字节,
- 在一个类文件中,我们可以简单地跳过一个方法的主体,不需要生成一个将使javac快乐的存根体,
- javac将编译存根源并生成稍后需要删除的类文件,
- 这种方式,旧的(快速)和新(较慢)的kapt模式使用相同的基本机制。
但是二进制存根有自己的缺点:
- 如果注释由@Retention(RetentionPolicy.SOURCE)标记,则它不在二进制文件中,
- javac不会在类层次结构下传播@Inherited注释。
到目前为止,我们还没有解决后一个问题,但前者的源保留注释是绝对关键的,因为许多流行的框架(如 DBFlow )他们的注释源保留。幸运的是,当 javac </ code>读取二进制文件时,它不会仔细检查注释,如果我们将类保留的注释写入类文件,尽管声明了保留,它会高兴地看到它。这是我们现在所做的<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 </ code>上还有一些工作尚待处理。
注释处理本身最大的问题是支持 @继承注释 。我们需要解决 javac </ code>,不会将它们传播到二进制类的层次结构中。
但是真正的问题在于外部的 kapt </ code>:许多框架,如 AndroidAnnotation 并且上述DBFlow想要直接将值注入到字段中,而Kotlin则是关于安全的,并且使这些字段 private </ code>正在阻碍。这就是为什么现在我们必须在Java中编写DBFlow“表类” Item.java 在我们的例子中
所以,我们正在考虑一个选择性功能,使得Kotlin生成的类中的非私有字段。
新的 kapt </ code>尚未发布,但欢迎您尝试并告诉我们您的想法。以下是您如何做的例子:
{% 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示例 这里 。
请告诉我们:
- 有什么对你有用
- 什么没有?
- 你喜欢还是不喜欢什么?
- 任何我们忽视的用例?
谢谢!