如何在 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)注释? 的相关文章

  • 如何使用 JAVA_OPTS 环境变量?

    我该如何使用JAVA OPTS变量来配置Web服务器 Linux服务器 我该如何设置 Djava awt headless true using JAVA OPTS JAVA OPTS是一些服务器和其他 Java 应用程序附加到执行调用的标
  • 哪个更快:instanceof 或 isInstance?

    抛开设计问题不谈 什么在现代 JVM 上执行得更快 foo instanceof Bar or Bar class isInstance foo Why Class isInstance是 JVM 固有的 它被编译为与instanceof完
  • Scala Array.apply 有何魔力

    来自 scala 2 10 4 的 array scala Array定义为 final class Array T length Int extends java io Serializable with java lang Clonea
  • Java EE 6 和单例

    谁能解释一下在 Java EE 6 应用程序中实现 Singleton 的完整过程 我假设我不应该以声明静态变量的典型方式创建单例 而应该使用 Singleton注解 我必须这样做吗 难道只是声明一下的情况 Singleton就是这样 我还
  • 如何创建用于测试的对象的 PagedList?

    我一直在使用 Google 的 arch 库 但是让测试变得困难的一件事是使用PagedList 对于此示例 我使用存储库模式并从 API 或网络返回详细信息 因此 在 ViewModel 中 我调用此接口方法 override fun g
  • androidx.navigation.fragment.NavHostFragment 无法从 xml 文件访问

    我正在尝试使用带有底部导航视图的 androidx 导航 因此 当我在 xml 文件中放置带有 android name androidx navigation fragment NavHostFragment 的片段时 它会给我一个错误
  • C# 反射属性顺序

    我正在使用代码https stackoverflow com a 531388 528131 https stackoverflow com a 531388 528131要成功地从基类中检索对象实例的所有属性 问题在于首先要迭代派生类型的
  • Vaadin 12 将对象传递给 JavaScript 函数:无法对类进行编码

    Vaadin 12 Kotlin 项目 In my myPage html我有JavaScript myObject redirectToCheckout sessionId 1111 2222 所以我需要调用javaScript函数red
  • PS幸存者空间几乎已满

    我看到我的应用程序的 PS 幸存者空间在大部分时间几乎已满 98 我不知道PS幸存者空间是什么 这是正常的吗 遇到这种情况应该怎么办 首先 参见例如这里 什么是幸存者空间 https stackoverflow com q 10695298
  • 我想实现下面的布局,按钮应该在屏幕底部,当惰性列被填充时,按钮不应该出去

    顶部有惰性列 惰性列下方有输入电话号码布局并从电话簿布局添加联系人 我希望当未添加联系人时此布局位于顶部 当我添加大量联系人时输入电话号码并添加电话簿布局中的联系人会随着惰性列滚动并移出屏幕 我不让他们走出屏幕 当接触较多时 它们必须粘在底
  • 用反射“铸造”

    考虑以下示例代码 class SampleClass public long SomeProperty get set public void SetValue SampleClass instance decimal value valu
  • Swagger/OpenAPI 注释 V3 - 在 swagger 注释中使用 Enum 值

    我正在使用 Swagger OpenApi V3 注释创建应用程序的 API 描述 从以下依赖项导入
  • 在 ArrayAdapter 上使用 ViewBinding

    我正在尝试重构我的应用程序以使用ViewBinding 我已经浏览了所有的片段和活动 然而 我有一个ArrayAdapter我不确定使用视图绑定来防止内存泄漏的正确约定 正确的使用方法是什么viewbinding在 ArrayAdapter
  • 获取枚举实例的名称[关闭]

    Closed 这个问题是无法重现或由拼写错误引起 help closed questions 目前不接受答案 假设我有这个枚举 public enum MyEnum ValueOne 1 ValueTwo 2 ValueThree 3 然后
  • Clojure 为什么命名为 Clojure

    为什么该语言的名称是 Clojure 我用谷歌搜索了一下 在 clojure 中询问 到目前为止 还没有运气 Rich Hickey 他是 Clojure 的设计者 对此的评论是 wiki 上的第一个参考链接 您是否根据以 closure
  • 如何确定 kotlin-multiplatform 项目中的构建类型

    我正在开发一个多平台项目 包括 iOS 和 JVM 我不直接针对 Android 根据构建类型 调试或发布 我想配置日志记录级别 即仅打印发布中的错误 由于没有一个BuildConfig课程可用 我怎样才能知道commonMain构建类型
  • 使用属性来减少枚举到枚举的映射以及枚举/常量到操作开关语句

    我想每个人都见过这样的代码 public void Server2ClientEnumConvert ServerEnum server switch server case ServerEnum One return ClientEnum
  • 指示泛型返回动态类型的对象

    这个问题是我原来问题的后续问题here https stackoverflow com questions 2541184 using a type object to create a generic 假设我有以下泛型类 简化 class
  • 递归例程获取PropertyInfo

    我正在尝试创建一个递归例程 它将检索指定对象 在 NET 3 5 中 下的所有成员的 PropertyInfos 直接成员的一切都正常 但它还需要解析嵌套类 及其嵌套类等 我不明白如何处理解析嵌套类的部分 这部分代码你会怎么写呢 publi
  • 使用反射覆盖最终静态字段是否有限制?

    在我的一些单元测试中 我在最终静态字段上的反射中遇到了奇怪的行为 下面是说明我的问题的示例 我有一个基本的 Singleton 类 其中包含一个 Integer public class BasicHolder private static

随机推荐

  • 如何更改动态 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