Search code examples
kotlindynamicreflectioncasting

Kotlin data class: How to cast property value to its actual property type using Kotlin reflection?


How can I convert the value of kProperty1.get(myClassInstance!!) to its actual type? Currently, the type is Any? and I need to pass it to a function that requires a specific type. I obtain kProperty1 using MyClass::class.declaredMemberProperties.firstOrNull { it.name == target } and myClassInstance is an instance of MyClass.

My code is like:

 val kProperty1 = MyClass::class.declaredMemberProperties.firstOrNull { it.name == propName }
     
            val valueFirst = myClassInstance1?.let { kProperty1.get(it) }
            val valueSecond = myClassInstance2?.let { kProperty1.get(it) }
            compareValues(valueFirst, valueSecond)

I can't call compareValues due to this error:

Type mismatch: inferred type is Any but Comparable<*> was expected

I need to compare two instances of MyClass by one property which name and type I don't know at compile time.

For example this property can be Long or String or LocalDate


Solution

  • Since the only thing you know about the property is that the type is a Comparable, cast the property type to Comparable<*>. The compareValues function will work even without knowing what the T of Comparable is, as long as the two arguments are actually the same type of Comparable, which we know is true since they came from the same KProperty.

    val kProperty1 = MyClass::class.declaredMemberProperties
        .firstOrNull { it.name == target } as KProperty1<MyClass, Comparable<*>>?
    requireNotNull(kProperty1) { "Property $target not found" }
    val value1 = myClassInstance1?.let { kProperty1.get(it) }
    val value2 = myClassInstance2?.let { kProperty1.get(it) }
    val result = compareValues(value1, value2)
    

    or

    val kProperty1 = MyClass::class.declaredMemberProperties
        .firstOrNull { it.name == target } as KProperty1<MyClass, Comparable<*>>?
    requireNotNull(kProperty1) { "Property $target not found" }
    val value1 = myClassInstance1?.let(kProperty1::get)
    val value2 = myClassInstance2?.let(kProperty1::get)
    val result = compareValues(value1, value2)