我试图通过反射设置枚举字段
I tried to set enum field by reflection
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 对枚举成员进行注解,并传递我们希望从中读取值的 属性 以及我们设置 属性.
值的字段的名称
我正在调试并发现它在尝试处理 CreatingCarStep 枚举时没问题,因为枚举值的 enumConstants 方法 returns 实际对象。所以我可以只取这个值的 class 并得到这个枚举的实际 class 并通过我的方法 enrichField 处理它。但是当它试图处理 Command 枚举时,我得到的只是枚举值。因此,如果我们采用枚举值的 class,将返回与命令相同的 class。在此处输入图片描述。
命令图片->
enter image description here
CreatingCarStep 图像 ->
enter image description here
它适用于 CreatingCarStep
,因为它的枚举常量有一个 non-empty 主体。这会强制 kotlin 编译器为每个枚举常量创建枚举 class 的子classes。此外,枚举常量上的注释将放在生成的 subclass 上。因此,enum::class.java
求值为 Class<*>
实例,表示 CreatingCarStep
的子 class 具有 FieldEnrich
注释。
当枚举常量有一个空主体,或者根本没有主体时,不会生成子class。枚举常量是枚举 class 本身的实例。因此,enum::class.java
的计算结果为 Command::class.java
,它没有 FieldEnrich
注释。
与其获取 clazz.enumConstants
并获取其 ::class.java
上的注释,不如获取枚举常量 字段 上的注释。这样,您就不会依赖于枚举常量是否有空体。
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)
}
}
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 对枚举成员进行注解,并传递我们希望从中读取值的 属性 以及我们设置 属性.
值的字段的名称我正在调试并发现它在尝试处理 CreatingCarStep 枚举时没问题,因为枚举值的 enumConstants 方法 returns 实际对象。所以我可以只取这个值的 class 并得到这个枚举的实际 class 并通过我的方法 enrichField 处理它。但是当它试图处理 Command 枚举时,我得到的只是枚举值。因此,如果我们采用枚举值的 class,将返回与命令相同的 class。在此处输入图片描述。
命令图片-> enter image description here
CreatingCarStep 图像 -> enter image description here
它适用于 CreatingCarStep
,因为它的枚举常量有一个 non-empty 主体。这会强制 kotlin 编译器为每个枚举常量创建枚举 class 的子classes。此外,枚举常量上的注释将放在生成的 subclass 上。因此,enum::class.java
求值为 Class<*>
实例,表示 CreatingCarStep
的子 class 具有 FieldEnrich
注释。
当枚举常量有一个空主体,或者根本没有主体时,不会生成子class。枚举常量是枚举 class 本身的实例。因此,enum::class.java
的计算结果为 Command::class.java
,它没有 FieldEnrich
注释。
与其获取 clazz.enumConstants
并获取其 ::class.java
上的注释,不如获取枚举常量 字段 上的注释。这样,您就不会依赖于枚举常量是否有空体。
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)
}
}