当前位置: 首页 > 知识库问答 >
问题:

如何在Kotlin数据类字段上列出(java)注释?

司徒啸
2023-03-14

我使用FireStore的基于Java的注释来标记字段,并使用将文档字段映射到Java类元素的方法:

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD, ElementType.FIELD})
public @interface PropertyName {
  String value();
}

我在Kotlin数据类的一个字段上使用它,它编译得很好:

data class MyDataClass(
    @PropertyName("z") val x: Int
)
public final data class MyDataClass public constructor(x: kotlin.Int) {
    @field:com.google.cloud.firestore.annotation.PropertyName public final val x: kotlin.Int /* compiled code */

    public final operator fun component1(): kotlin.Int { /* compiled code */ }
}
    null
data class MyDataClass(
    @get:PropertyName("z") val x: Int
)

注释现在显示在Java类对象的生成getter中。这至少在实践中是可行的,但我很好奇为什么Kotlin让我将注释编译为针对字段的注释,但不允许我在运行时将其返回(除非我在kotlin-reflect API中遗漏了什么?)。

如果我改用这个基于Kotlin的注释:

@Retention(AnnotationRetention.RUNTIME)
@Target(AnnotationTarget.PROPERTY)
annotation class PropertyName(val value: String)

这样,注释就会在运行时显示在Kotlin字段上。这很奇怪,因为Java的ElementType.Field似乎并没有完全映射到Kotlin的AnnotationTarget.Field。

Log.d("@@@@@", "\n\nDump of $kclass")
val ctor = kclass.constructors.first()
Log.d("@@@@@", "Constructor parameters")
ctor.parameters.forEach { p ->
    Log.d("@@@@@", p.toString())
    Log.d("@@@@@", p.annotations.size.toString())
    p.annotations.forEach { a ->
        Log.d("@@@@@", "  " + a.annotationClass)
    }
}

Log.d("@@@@@", "kotlin functions")
kclass.functions.forEach { f ->
    Log.d("@@@@@", f.toString())
    if (f.annotations.isNotEmpty()) {
        Log.d("@@@@@", "*** " + f.annotations.toString())
    }
}

Log.d("@@@@@", "kotlin members")
kclass.members.forEach { f ->
    Log.d("@@@@@", f.toString())
    if (f.annotations.isNotEmpty()) {
        Log.d("@@@@@", "*** " + f.annotations.toString())
    }
}

Log.d("@@@@@", "kotlin declared functions")
kclass.declaredFunctions.forEach { f ->
    Log.d("@@@@@", f.toString())
    if (f.annotations.isNotEmpty()) {
        Log.d("@@@@@", "*** " + f.annotations.toString())
    }
}

val t = kclass.java
Log.d("@@@@@", "java constructors")
t.constructors.forEach { f ->
    Log.d("@@@@@", f.toString())
}

Log.d("@@@@@", "java methods")
t.methods.forEach { f ->
    Log.d("@@@@@", f.toString())
    if (f.annotations.isNotEmpty()) {
        Log.d("@@@@@", "*** " + f.annotations.toString())
    }
}

Log.d("@@@@@", "java fields")
t.fields.forEach { f ->
    Log.d("@@@@@", f.toString())
    if (f.annotations.isNotEmpty()) {
        Log.d("@@@@@", "*** " + f.annotations.toString())
    }
}

共有1个答案

丌官瀚
2023-03-14

这里的问题是,我的期望(可能还有文档)没有让我准备好Kotlin编译器将如何处理各种类型的注释。我的假设是,Kotlin数据类属性上的字段目标注释目标将直接将注释应用于Kotlin合成属性。这种假设是不正确的。

Kotlin对合成属性的字段注释所做的是将字段注释向下推到生成的类文件中该属性的实际支持字段。这意味着对带注释的Kotlin属性的任何类型的反射都不会找到注释。您必须深入Java类对象才能找到它。

如果您想要注释Kotlin类属性,并通过KClass反射找到它,您必须使用属性类型注释,这是Kotlin独有的。这样,如果您在KClass的members列表中找到该属性,它将具有该注释(但不是基础支持字段!)。

谁来更新一下文件。-)

 类似资料:
  • 如何动态修改实体类注解上的参数? 现在有个需求是EXCEL导入图片 这里用的是easypoi.excel 但是@Excel注解上的savePath是写死的,因为本地、测试、线上的路径都不一样,每次打包都要改 如何根据环境动态的去配置这个路径,所以我想在项目加载时动态去获取服务器的相对路径并设置

  • 问题内容: 我正在参加的编程班上为我提供了一个项目,但我不知道从哪里开始,并希望有人可以将我推向正确的方向。我只发布项目的一部分,以便有人可以向我展示一些代码,以了解如何完成编程,因为我之前参加过编程课程,但是我没有实践。 创建一个具有以下类的名为Registrar的应用程序: 一个学生类,该类至少为学生存储以下数据字段: 名称 学生证号码 学分数 还应该提供以下方法: 初始化名称和ID字段的构造

  • 我对使用数据注释到DTO类感到困惑。这是我的示例类。 我在网上读到,特别是在DTO类上使用数据注释将允许通过使用生成的设置器来更改字段的值。 我应该删除lombok Data注释吗?并手动实现getter和setter。 谢谢:)

  • 最近,我将我的KMP项目分为fullstack项目和核心库(主要由公共数据类组成),并发现我需要在公共模块中定义的一个数据类上使用JVM库中的注释。 在Kotlin公共代码中似乎不可能使用Java库中的注释。 解决此类问题的可能方法是什么,最好避免通过声明此类数据类,然后在平台中重复其实现,但使用不同的注释?

  • 我想完成但不明白它是如何工作的 使用这段代码,我想注释生成它们各自的setter和getter,这样我就可以使用像 编辑2013-10-25 我的目标是构建一个能够做到这一点的库,因为我太好奇了,想了解如何在内部工作,所以我将能够用这个特性来支持我的框架,因为jet只是一个小实用程序,但在未来我希望它能为我节省大量的工作,你可以在github WSD Android上看到

  • 一个程序的可读性,关键取决于注释。如果一个程序想二次开发,要读懂前面的程序代码,就必须在程序中有大量的注释文档,所以对于一个优秀的程序员来说,学会在程序中适当地添加注释是非常重要的。 注释除了帮助别人了解编写的程序之外,还对程序的调试、校对等有相当大的帮助。当程序具体运行时,计算机会自动忽略注释符号之后所有的内容。教程第二章中曾经提到过注释,读者也许印象不太深,在这里复习一遍。 本节将简单地介绍类