代码之家  ›  专栏  ›  技术社区  ›  Marcoral

如何使用kotlin.reflet API设置kotlin对象类属性的值?

  •  1
  • Marcoral  · 技术社区  · 6 月前

    如何为类设置属性值 对象 关键字使用kotlin.reflet API?我希望这类似于在常规类中设置值,但事实并非如此。在设置字段值时,我收到一个异常,指示参数数量错误,在我看来,这甚至像语言本身的一个bug(我希望,如果出于某种原因,无法为这种类型的类设置值,我宁愿收到OperationNotSupported样式的异常)。

    这里有一个简单的例子来重现这个问题:

    import kotlin.reflect.KClass
    import kotlin.reflect.KMutableProperty1
    import kotlin.reflect.full.declaredMemberProperties
    import kotlin.reflect.jvm.isAccessible
    
    fun main() {
        test(RegularClass::class, RegularClass())   //This one prints "Hello world" as expected!
        
        /* Both of these methods throw "java.lang.IllegalArgumentException: Callable expects 1 arguments, but 2 were provided"
         * How to set value of kotlin "object" property? */
        test(ObjectClass::class, null)
        test(ObjectClass::class, ObjectClass)
    }
    
    private fun test(kClass: KClass<out Greeter>, receiver: Greeter?) {
        val property = kClass.declaredMemberProperties
            .filterIsInstance<KMutableProperty1<Any?, Any?>>()
            .first {
                it.name == "variable"
            }
    
        property.isAccessible = true
        property.set(receiver, "Hello world!")
        receiver?.helloWorld()
    }
    
    interface Greeter {
        fun helloWorld()
    }
    
    class RegularClass: Greeter {
        private var variable: String = "Wrong value"
    
        override fun helloWorld() {
            println(variable)
        }
    }
    
    object ObjectClass: Greeter {
        private var variable: String = "Wrong value"
    
        override fun helloWorld() {
            println(variable)
        }
    }
    
    1 回复  |  直到 6 月前
        1
  •  2
  •   Sweeper    6 月前

    这确实是一个Kotlin bug。私人财产在 object 编译为Java静态字段,不需要设置接收器参数。YouTrack上关于这个问题有三个不同的问题 吸气剂 : KT-55449 , KT-55872 ,以及 KT-23267 .

    现在的一个解决方法是检测这样一个字段,并使用Java反射进行设置。

    private fun test(kClass: KClass<out Greeter>, receiver: Greeter?) {
        val property = kClass.declaredMemberProperties
            .filterIsInstance<KMutableProperty1<Any?, Any?>>()
            .first {
                it.name == "variable"
            }
    
        property.isAccessible = true
        val field = property.javaField
        if ((field?.modifiers?.and(Modifier.STATIC or Modifier.PRIVATE) ?: 0) > 0) {
            field?.set(null, "Hello World!")
        } else {
            property.set(receiver, "Hello world!")
        }
        receiver?.helloWorld()
    }
    
    推荐文章