我试图通过反射设置枚举字段

发布于 2025-01-30 17:41:48 字数 1844 浏览 1 评论 0原文

enum class Command(private vararg val commands: String) {

  @FieldEnrich("changeLanguages", "commands")
  CHANGE_LANGUAGE;
}

enum class CreatingCarStep(private vararg val values: String) : AbstractStep<CreatingCarStep> {
  @FieldEnrich("brand-name", "values")
  BRAND_NAME {
    override fun next() = MODEL
    override fun previous() = BRAND_NAME
  };
}

我有两个带有Vararg属性和@fieldenrich注释的枚举。

注释看起来像是

@Target(FIELD, CLASS)
@Retention(RUNTIME)
annotation class FieldEnrich(
  val property: String,
  val field: String
)

通过对象处理注释,

object FieldEnricher {

  lateinit var configurationProvider: ConfigurationProvider

  fun enrichClass(clazz: Class<*>) {
    clazz.enumConstants.forEach {
      enrichField(it, clazz)
    }
  }

  private fun enrichField(enum: Any, clazz: Class<*>) {
    val enumClass = enum::class.java
    if (enumClass.isAnnotationPresent(FieldEnrich::class.java)) {
      val fieldEnrich = enumClass.getAnnotation(FieldEnrich::class.java)
      val values = configurationProvider.getProperty(fieldEnrich.property, Array<String>::class.java)
      val field = clazz.declaredFields.firstOrNull { it.name == fieldEnrich.field }
      field?.isAccessible = true
      field?.set(enum, values)
    }
  }
}

逻辑如下。我们用注释@fieldenrich注释了一个枚举成员,并通过我们想从我们设置属性值的字段名称和字段的名称中传递属性。

我正在调试,并发现它何时试图处理创建Carstep Enum是可以的,因为Enumconstants方法返回枚举值的实际对象。因此,我可以参加此值的类别,并获得此枚举的实际类别,并通过我的方法丰富的菲尔德进行处理。但是,当它试图处理命令枚举时,我得到了枚举值。因此,如果我们参加枚举值类,则将返回相同的命令类别。&nbsp;在此处输入图像描述。

命令图像 - &gt; 在此处输入图像描述

createCarstep image -&gt; 在此处输入图像描述

enum class Command(private vararg val commands: String) {

  @FieldEnrich("changeLanguages", "commands")
  CHANGE_LANGUAGE;
}

enum class CreatingCarStep(private vararg val values: String) : AbstractStep<CreatingCarStep> {
  @FieldEnrich("brand-name", "values")
  BRAND_NAME {
    override fun next() = MODEL
    override fun previous() = BRAND_NAME
  };
}

I have two enums with vararg property and @FieldEnrich annotation.

Annotation looks like

@Target(FIELD, CLASS)
@Retention(RUNTIME)
annotation class FieldEnrich(
  val property: String,
  val field: String
)

Annotation is processing by object

object FieldEnricher {

  lateinit var configurationProvider: ConfigurationProvider

  fun enrichClass(clazz: Class<*>) {
    clazz.enumConstants.forEach {
      enrichField(it, clazz)
    }
  }

  private fun enrichField(enum: Any, clazz: Class<*>) {
    val enumClass = enum::class.java
    if (enumClass.isAnnotationPresent(FieldEnrich::class.java)) {
      val fieldEnrich = enumClass.getAnnotation(FieldEnrich::class.java)
      val values = configurationProvider.getProperty(fieldEnrich.property, Array<String>::class.java)
      val field = clazz.declaredFields.firstOrNull { it.name == fieldEnrich.field }
      field?.isAccessible = true
      field?.set(enum, values)
    }
  }
}

The logic is as follows. We annotate an enum member with the annotation @FieldEnrich and pass the property we would like to read value from and the name of the field to which we set the value of the property.

I was debugging and found out when it was trying to process CreatingCarStep enum is okay, because the enumConstants method returns actual objects of the enum values. So i can just take the class of this value and get the actual class of this enum and process it by my method enrichField. But when it was trying to process Command enum, I got just enum values. So if we take the class of enum value, the same class of Command will be returned. Enter the image description here.

Command image ->
enter image description here

CreatingCarStep image ->
enter image description here

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

煮茶煮酒煮时光 2025-02-06 17:41:48

它适用于CreateCarstep,因为其枚举常数具有非空体。这迫使Kotlin编译器为每个枚举常数创建枚举类别的子类。此外,枚举常数上的注释将放在生成的子类上。因此,enum :: class.java评估class&lt;*&gt;实例,代表具有createCarstep的子类,该子类具有fieldenrich注释。

当枚举常数具有空体或根本没有身体时,就不会产生子类。枚举常数是枚举类本身的实例。因此,enum :: class.java评估命令:: class.java,它没有field> fieldenrich andotation。

与其获得clazz.enumconstants并在其:: class.java上获取注释,还应在枚举常数 fields 上获取注释。这样,您不取决于枚举常数是否具有空体。

fun enrichClass(clazz: Class<*>) {
    clazz.declaredFields.forEach {
        if (it.isEnumConstant) {
            enrichField(it, clazz)
        }
    }
}

private fun enrichField(enumField: Field, clazz: Class<*>) {
    if (enumField.isAnnotationPresent(FieldEnrich::class.java)) {
        val fieldEnrich = enumField.getAnnotation(FieldEnrich::class.java)
        val values = configurationProvider.getProperty(fieldEnrich.property, Array<String>::class.java)
        val field = clazz.declaredFields.firstOrNull { it.name == fieldEnrich.field }
        field?.isAccessible = true
        field?.set(enumField.get(null), values)
    }
}

It works for CreatingCarStep because its enum constants have a non-empty body. This forces the kotlin compiler to create subclasses of the enum class for each of the enum constants. Additionally, the annotations on the enum constant will be put on the generated subclass. Therefore, enum::class.java evaluates to a Class<*> instance that represents a subclass of CreatingCarStep that has a FieldEnrich annotation.

When the enum constants have an empty body, or do not have a body at all, no subclasses are generated. The enum constants are instances of the enum class itself. Hence, enum::class.java evaluates to Command::class.java, which has no FieldEnrich annotation.

Rather than getting clazz.enumConstants and getting the annotations on their ::class.java, you should get the annotations on the enum constant fields. This way, you do not depend on whether or not the enum constants have empty bodies.

fun enrichClass(clazz: Class<*>) {
    clazz.declaredFields.forEach {
        if (it.isEnumConstant) {
            enrichField(it, clazz)
        }
    }
}

private fun enrichField(enumField: Field, clazz: Class<*>) {
    if (enumField.isAnnotationPresent(FieldEnrich::class.java)) {
        val fieldEnrich = enumField.getAnnotation(FieldEnrich::class.java)
        val values = configurationProvider.getProperty(fieldEnrich.property, Array<String>::class.java)
        val field = clazz.declaredFields.firstOrNull { it.name == fieldEnrich.field }
        field?.isAccessible = true
        field?.set(enumField.get(null), values)
    }
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文