4

I am new to Kotlin. Facing an issue with reflection and generics. Below is my code.

abstract class Action {
  fun sleep(body: Person.() -> Unit){
    var p = Person("a");
    p.body()
    println(p.name + " is zzzzzzz...")
  }
}

class Person(var name:String =""){
  companion object:Action();
}

inline fun <reified T> test(){
  val companionObject = T::class.companionObject
  if (companionObject != null) {
    println(companionObject.javaObjectType)
    val functionEx = companionObject.functions.filter { it.name.equals("sleep") }.first()
    // How to invoke functionEx with block and "this"
  }
}

fun main(args: Array<String>) {
  Person.sleep {
    this.name = "abc"
  }
  test<Person>()
}

I want to invoke the sleep function through functionEx with the same block code which is in the main. I am struggling with the this operator.

I am using some API and have emulated the problem through Action and Person. So can't change their implementation. Its just the test function which is under my control.

BhaskerYadav
  • 569
  • 3
  • 24

1 Answers1

5

This should work:

inline fun <reified T> test() {
    val companionObject = T::class.companionObject
    if (companionObject != null) {
        val body: Person.() -> Unit = { println("body called on $name!") }
        val companionInstance = T::class.companionObjectInstance
        val functionEx = companionObject.functions.first { it.name.equals("sleep") }
        functionEx.call(companionInstance, body)
    }
}

To call the function using call(...), you need to pass the companion object instance as the first argument (which stands for the sleep function's receiver) and an instance of the function type Person.() -> Unit as the second one.

Note that companionObject returns not the companion object instance but its KClass. To get the instance, use companionObjectInstance instead.

hotkey
  • 140,743
  • 39
  • 371
  • 326