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

2024-03-10

我使用 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
)

在 IntelliJ 和 Android Studio 中,我可以看到它显示在反编译的类转储中:

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 */ }
}

我目前的印象是,这个注释应该可以通过 Kotlin 反射以某种方式发现。据我所知,事实并非如此。我尝试过迭代注释:

  1. 每个 Kotlin 数据类构造函数字段
  2. 每个 Kotlin 字段
  3. 每个 Kotlin 函数
  4. 每个Java构造函数
  5. 每个Java字段
  6. 每个Java方法

它只是没有出现在任何地方。

当我像这样更改注释的用法时(请注意现在的目标说明符“get”):

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。

(顺便说一句,如果我将其更改为 AnnotationTarget.VALUE_PARAMETER,我还可以在数据类构造函数参数中发现此注释。)

对我来说,这感觉像是一个错误,但我愿意看看我是否在这里做错了什么。或者这可能只是不受支持。我正在使用 Kotlin 1.3.11。 JVM 和 Android 上的行为相同。

查找注释的代码:

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())
    }
}

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

Kotlin 对合成属性的 FIELD 注解所做的就是将 FIELD 注解下推到实际属性背景场 https://kotlinlang.org/docs/reference/properties.html#backing-fields对于生成的类文件中的属性。这意味着对带注释的 Kotlin 属性的任何类型的反射都根本找不到该注释。您必须深入到 Java 类对象中才能找到它。

如果您想注释 Kotlin 类属性,并通过 KClass 反射找到它,则必须使用 PROPERTY 类型注释,这是 Kotlin 独有的。有了这个,如果您在membersKClass 的列表,它将具有该注释(但没有底层支持字段!)。

更进一步,与Kotlin 数据类,构造函数是定义类的属性的最重要的东西。因此,如果您想在运行时通过反射创建数据类实例,最好通过其构造函数注释其属性。这意味着将 VALUE_PARAMETER 类型的注释应用于数据类构造函数属性,可以通过构造函数参数本身的反射来发现它们。

从更一般的意义上讲,Java 定义的注释类型only适用于Java类反射,而Kotlin扩展的注解类型only适用于KClass反射。 Kotlin 编译器将禁止您在 Java 元素上使用 Kotlin 特定的注释类型。这里的例外是,它允许您将 Java 注释类型应用于 Kotlin 概念(带有支持字段的属性),这些概念“归结为”Java 原生概念。 (FWIW,如果您将 Java 本机注释代码复制到 Kotlin 中并让它自动转换,如果不考虑这一点,转换可能没有意义。)

如果您最喜欢的 Java 库仅公开适用于 Java 层概念的注释,请考虑要求他们提供 Kotlin 扩展,以帮助您在更纯粹的 Kotlin 级别上使用他们的注释。尽管在 Java 代码中使用这可能会很棘手。

有人请更新文档。 :-)

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何在 Kotlin 数据类字段上列出(java)注释? 的相关文章

  • Kotlin 高阶函数参数:传递子类型

    我在 Kotlin 中遇到了函数参数的问题 我将借助一些代码来解释这个问题 我创建了一个类层次结构 当我将子类型传递给需要父类型的函数时 没有问题 open class A val i Int class B val j Int A j f
  • 将附件视图按钮添加到 MKMapView 调出注释?

    我最近遇到过这个网站 http www everydayone com 2009 08 mapkit annotation with buttons example 我一直在尝试向我的呼出视图添加一个按钮 来自图像 网站示例上的代码工作得很
  • 在 Android 中处理多个回收器视图 [Kotlin]

    我遇到过这样的情况 一个布局上有 3 个 RecyclerView 他们以某种方式相互依赖 数据来自房间数据库 问题原型 问题陈述 假设您有类似 Floor1 Floor2 Floor3 等 的楼层 并且每个楼层内都有类似 Room1 Ro
  • 获取带有注释的所有类并将它们添加到 android 中的 hashMap

    我不确定这是否可能 但我基本上希望能够轻松地将新项目添加到列表中 只需添加带有特殊注释的类即可 我能想到的唯一例子就是我目前正在做的事情 用户可以完成很多 挑战 目前我的应用程序中有一个用于 挑战 的包 我希望能够在该包中创建一个新类 给它
  • LiveData无法观察到变化

    我正在更新一个ViewModel 中 DialogFragment 的 LiveData 值 但无法获取Fragment中的值 视图模型 class OtpViewModel private val otpUseCase OtpUseCas
  • TypeDescriptor 不返回继承接口的成员

    我的问题是 TypeDescriptor 不从继承的接口返回成员 这是它应该如何工作的吗 或者这是一个错误 TestFixture public class DescriptorTests Test public void Test cou
  • 有Commons AnnotationUtils之类的库吗? (爪哇)

    除了直接使用注释 api 并编写自己的注释或使用 Springs 之外 我找不到用于查询注释的通用实用程序 静态方法 库 Springs 注释实用程序 http static springsource org spring docs 2 5
  • 如何使用 Kotlin 在 ListAdapter 中使用 Filterable?

    我会用一个SearchView过滤我的RecyclerView 在 stackoverflow 和其他网站上我发现只是使用的示例Filterable与 Java 和RecyclerView Adapter当我使用时ListAdapter 所
  • 如何找到类路径上具有特定方法注释的所有类?

    我想在Java中实现一个基于注释的初始化机制 具体来说 我定义了一个注释 Retention RetentionPolicy RUNTIME Target ElementType METHOD public interface Initia
  • 我可以在方法体内使用注释吗?

    允许 Java 注释的语义将它们放置在某处在函数体内 例如注释特定的函数调用 语句或表达式 例如 class MyClass void theFunc Thing thing String s null Catching NullPoint
  • 如何判断我是在 64 位 JVM 还是 32 位 JVM 中运行(在程序内)?

    如何判断应用程序运行的 JVM 是 32 位还是 64 位 具体来说 我可以使用哪些函数或属性来在程序中检测到这一点 对于某些版本的 Java 您可以使用标志从命令行检查 JVM 的位数 d32 and d64 java help d32
  • 如何在发布版本中使用 Zebra EMDK?

    所以我有一台 Zebra MC330M 设备 我之前创建了一个应用程序 我想使用 PDA 内置的条形码扫描仪 如果在调试模式下运行我的应用程序 一切正常 我可以读取条形码 但是如果我创建暂存或释放版本 apk 则条形码读取器不活动 因此如果
  • 在动态事件处理程序中引用“this”

    在我的 myClass 类中 我使用 Reflection Emit 为 myClass 类成员之一动态编写事件处理程序 我已经成功地做到了这一点 现在 我想修改事件处理程序以调用 myClass 类中的实例方法之一 但是 我无法弄清楚如何
  • jvm 如何以及何时何地更改 Linux 的最大打开文件值?

    在linux中 每个登录用户的每个进程的最大打开文件数有限制 如下所示 ulimit n 1024 当我学习java nio时 我想检查这个值 因为channel在Linux中也是一个文件 所以我编写了一个客户端代码来不断创建socketC
  • Kotlin 中是否有类似于 #region #endregion 的语法?

    我知道我可以使用 region endregion 包围 C 中的代码片段 Kotlin 中是否有类似的语法 谢谢 region MyRegion protected void Page Load object sender EventAr
  • Kotlin JavaScript 到 TypeScript 定义文件

    我已经找到了ts2kt 库 https github com Kotlin ts2kt这将从任意位置创建 Kotlin 头文件 d ts文件 但是 我想朝相反的方向走 我想构建一个可以编译为 JavaScript 的 Kotlin 库 但我
  • 如何在Java中计算对象的数字年龄[关闭]

    Closed 这个问题需要多问focused help closed questions 目前不接受答案 我想知道Java中对象的年龄 当我们使用new关键字时 Java中用户定义的对象被创建 但是什么时候它会被销毁 是跨越JVM的perm
  • Java 类:匿名类、嵌套类、私有类

    有人能解释一下Java中匿名类 嵌套类和私有类之间的区别吗 我想知道与每个相关的运行时成本以及每个编译器的方法 这样我就可以掌握哪个最适合用于例如性能 编译器优化的潜力 内存使用以及其他 Java 编码人员的普遍可接受性 我所说的匿名类是指
  • 在Android中绘制圆角矩形

    我已经发现这个问题 https stackoverflow com questions 5618402 how to draw rounded rectangle in android ui解决方案是这段代码
  • .Net 中是否有一个框架属性可以隐藏成员以使其免受反射?

    是否有一个属性可以隐藏成员 特别是属性 typeof MyType GetProperties 在 net中 我正在寻找快速修复方法 即不创建自定义属性等 thanks No 反射允许人们看到一切 包括标记为私有的成员 最终反射使用与 CL

随机推荐

  • 如何更改动态 SQL 中的序列?

    我正在尝试创建一个脚本来将数据从一个数据库迁移到另一个数据库 我当前无法做的一件事是将序列的 nextval 设置为另一个数据库中序列的 nextval 我从 user sequences 中得到了值的差异 并生成了以下动态 SQL 语句
  • 如何从 NSArray 中选择 UIImgeView

    I have UIImageView用作可拖动对象 它们位于NSArray所以 当拖动它们时它们工作得很好 但我想要的是当我拖动它们并完成拖动方法而不是将图像放在UIImageView我只想在拖动完成时将其替换为自定义图像 所以我的问题是如
  • 具有相同高度的 SwiftUI HStack 元素

    我希望两个按钮具有相同的高度 类似于Equal HeightUIKit 中的约束 不想指定框架 让 SwiftUI 处理它 但 HStack 中的元素应该具有相同的高度 按钮应具有相同的宽度和高度 并适应较长的文本并增加其框架大小 两个按钮
  • AssemblyInstaller 中的服务类型

    我想通过编程方式安装 Windows 服务example https stackoverflow com questions 1195478 how to make a net windows service start right aft
  • 在广播接收器中检测 USB - 我缺少什么?

    我的代码遗漏了一些东西 需要你的眼睛来定位 我创建了一个 USBOnReciever 广播接收器 public class USBOnReceiver extends BroadcastReceiver Override public vo
  • wc_countries - 国家选择下拉菜单 - woocommerce

    我正在努力设置一个带有默认 WooCommerce 国家和州选择下拉列表的表单 基本上 我想显示国家 地区选择 然后根据国家 地区选择显示州选择 因此 如果用户选择英国 则会显示包含州选择的新下拉列表 我到目前为止
  • 如何保留setTimeout参数值直到执行?

    我有一些在按键时执行的代码 并在用户键入时将数据保存到数据库中 我添加了一个 setTimeout 函数 前面有一个clearTimeout 因此并非用户输入的每个字符都会发送 Ajax 请求来保存数据 虽然 setTimeout 对于一个
  • 浏览器中的 HTTP PATCH 支持

    我正在为我的应用程序设计 REST 端点 并且我需要对一些端点使用 PATCH 所有支持 HTTP 1 1 的浏览器都能够支持 PATCH 吗 HTTP 1 1 没有定义PATCH method HTTP 1 1 确实为客户端和 或服务器添
  • MySQL 中的 CAST 为 DECIMAL

    我正在尝试在 MySQL 中转换为 Decimal 如下所示 CAST COUNT 1 5 AS DECIMAL 2 我正在尝试将表中的行数 乘以 1 5 转换为该点后带有两位数字的浮点数 SQL代码 SELECT CONCAT Guard
  • Boost::序列化和 MFC Doc/View 架构

    我正在移植现有的 MFC C 应用程序以对 XML 文件使用 Boost Serialization 我的 CDocument 对象包含应用程序的所有数据 我已将序列化函数实现为 template
  • 是否可以从同一包中的模块访问 __init__.py 中的变量?

    我有一个 hello1 包 其中包含 good py 模块 hello1 init py good py The init模块有一个变量A 1 我需要访问good py中的变量hello1 A import hello1 class Goo
  • 如何使用brew cask指定版本?

    安装某些东西时如何指定版本号brew cask install 对于最新版本的 Homebrew 下面是杰思罗的指示 https stackoverflow com a 58373705 8280495可能不起作用 因为我们会收到如下错误
  • 将 DateTime 值作为参数传递给 OleDbCommand

    我在将 DateTime 值作为 DbParameter 传递给查询时遇到问题 看来 DateTime 值的时间部分被剥夺了 下面是 C 中的示例代码 DbProviderFactory factory OleDbFactory Insta
  • 在 Metal Shading Language 中创建全局可访问的常量缓冲区

    我有一个关于 Metal 中的常量缓冲区的问题 假设我有类似的东西 list of includes goes here using namespace metal struct ConstantBuffer float ANY VALUE
  • 如何在我的 docker 映像中安装 python-tk [重复]

    这个问题在这里已经有答案了 当我在 docker 映像中运行 python 脚本时出现此错误 ImportError No module named tkinter please install the python tk package
  • 将 numpy 加载到 IronPython 中

    我最近安装了 Ironpython 工具 但在加载外部模块 numpy 时遇到问题 这是我的测试代码 import numpy numpy test 当编写我的简单测试时 智能感知找不到 numpy 但是当它从 vs2010 运行时 我得到
  • 将 opencv 仿射矩阵转换为 CGAffineTransform

    我想采用 OpenCV 中的仿射矩阵 Mat T getAffineTransform src pt dst pt 然后将其转换为 CGAffineTransform 以在 Core Graphics Objective C iOS 中使用
  • Postgresql 在删除行之前创建触发器

    所以我有这两个表 Table user columns id name surname password token earnedmoney Table addlisting columns id user fk price date ad
  • java中如何初始化动态数组?

    如果我有一个类需要返回可变维度的字符串数组 并且该维度只能在运行该类的某些方法时确定 那么如何在类的构造函数中声明动态数组 如果问题还不够清楚 在 php 中我们可以简单地声明一个字符串数组为 my string array array 并
  • 如何在 Kotlin 数据类字段上列出(java)注释?

    我使用 Firestore 的基于 Java 的注释来标记字段和将文档字段映射到 Java 类元素的方法 Retention RetentionPolicy RUNTIME Target ElementType METHOD Element