kotlin 注释处理器中的可空类型
Posted
技术标签:
【中文标题】kotlin 注释处理器中的可空类型【英文标题】:Nullable types in kotlin annotation processor 【发布时间】:2018-01-28 06:31:55 【问题描述】:我正在为 Kotlin 开发注解处理器,因为处理的元素是在 Java 中,所以我没有收到可以为 ?
的可空值,而是使用 @Nullable
注解,这很好,但我在接收时遇到了问题对于普通参数,类型和高阶函数中的 null 参数。
var someNullField: String? = ""
我将在过程中收到java.lang.String
,并在其注释中添加@org.jetbrains.annotations.Nullable
。
但是 List<String?>
例如会返回我 java.util.List<java.lang.String>
没有任何注释,不在主元素中,不在类型参数中,导致未知的可空性状态
我尝试使用javax.lang.model.util.Types
找到某种结果,但什么也没有。
我现在使用的一些代码:
val utils = processingEnvironment.typeUtils
val type = fieldElement.asType()
if (type is DeclaredType)
val typeElement = utils.asElement(type)
type.typeArguments
.forEach
//Trying different ways and just printing for possible results
val capture = utils.capture(it)
val erasure = utils.erasure(it)
val element = utils.asElement(it)
printMessage("element: $element isNullable: $element.isNullable() isNotNull: $element.isNotNull()\ncapture: $capture isNullable: $capture.isNullable() isNotNull: $capture.isNotNull()\nerasure: $erasure isNullable: $erasure.isNullable() isNotNull: $erasure.isNotNull()")
我们将不胜感激。
【问题讨论】:
【参考方案1】:一些必要的历史:从 Java 6 开始(当 Mirror API 公开时)Java 注释不能用于任何东西,但相同类型的***元素可以通过反射访问。您可以注释类、方法和字段,但不能注释类型参数 (List<String>
) 或局部变量 (String value = ...
)。 Sun/Oracle 工程师已经承认了这个限制,并且在 Java 8 中诞生了所谓的“类型注释”。
类型注解可以针对任何type:type局部变量,数组组件类型,类型变量type 甚至是返回类型(后面的注解也是类似的,但与方法上的老式注解不同!)。类型注释是通过新的@Target
值创建的:ElementType#TYPE_USE。
当 Kotlin 人写作时
List<String?>
真的是这样
List<@Nullable String>
可以读作:“可空字符串元素列表”。
由于 type 本身就是目标,因此您应该通过检查它的原始 TypeMirror
来获取注释(不要打扰已擦除或捕获的 TypeMirror,它们没有足够的连接到源代码以保留注释)。巧合的是,对 Mirror API 进行了重构,产生了新的接口AnnotatedConstruct,方便地把 TypeMirror 做成了它的后代。
现在有个坏消息:到 Java 8 发布时,对检查类型注释的支持显然还没有为生产做好准备,所以它被淘汰了。 JSR 已被重写以暗示“TypeMirror#getAnnotationMirrors”应该不返回任何内容。
从公共 API 中删除的部分支持仍然可以通过 Oracle 的供应商特定的Tree API 获得(仅在 javac 中支持)。由 Tree#getTypeMirror 返回的 TypeMirror 可能包含您期望的注释。但是由于它是错误的,您只能通过一系列 hack 获得注释,最终,这不会在任何时候都有效(例如在嵌套类型参数的情况下)。有关该方向的一些研究,请参阅 this question。
The fix 因为这个烂摊子被合并到 Java 9 中。我还没有测试它,但看起来 TypeMirror#getAnnotationMirrors 最终可能会起作用。没有计划将修复程序向后移植到较旧的 Java 版本。
【讨论】:
感谢详细描述的答案,我想出了某种解决方案/破解方法:基本上创建一个名为 NullableOfCollection<Optional<*>>
时会创建大量样板文件,创建大量不必要的对象。如果您主要关心集合(90% 的泛型用例),您可以通过不支持 null
的专用集合类型传达可空性(野外已经有多个这样的集合)。此外,如果您真的关心该用例,您可以通过 Tree API 自行破解对类型镜像自省的支持。这是可能的(但需要解析源代码树)。
好的,谢谢,我可能会先尝试树 API,如果它不起作用,我会检查我将使用什么,因为可选的是 Java 8,我需要对 Java 7 的支持
@GilGoldzweig 注意,如果你走这条路,你的用户将不得不使用 Java 8 javac 构建项目(因为旧版本的编译器不支持类型注释)。以上是关于kotlin 注释处理器中的可空类型的主要内容,如果未能解决你的问题,请参考以下文章
Kotlin空安全 ① ( Kotlin 的空安全机制 | 变量可空性 | 默认变量不可赋空值 | 声明可空类型变量 )