Kotlin reflection/generics cheat sheet

Consider this class

class ImAClass() {
    var property: Int = 0


    fun function(param: Int): Int {
        println("Function called, params: $param ")
        return param
    }
}

We want to manipulate it using generics, so we create a class like this:

class Reflection<T : Any>(
    private val kClass: KClass<T>
) {
    fun name(): String {
        return kClass.simpleName ?: ""
    }

    fun instance(): T {
        return kClass.createInstance()
    }

    fun properties(): Collection<KProperty<*>> {
        return kClass.memberProperties
    }

    fun getProperty(propName: String): KProperty<*>? {
        return kClass
            .memberProperties
            .filter { it.name == propName }
            .firstOrNull()
    }

    fun getFunction(functionName: String): KFunction<*>? {
        return kClass
            .functions
            .filter { it.name == functionName }
            .firstOrNull()
    }

    fun functions(): Collection<KFunction<*>> {
        return kClass.functions
    }

    fun getValueByName(propName: String, instance: T): Any? {
        val prop = getProperty(propName)

        if (prop == null)
            return null

        if (prop !is KProperty1<*, *>)
            return null

        val kProperty = prop as KProperty1<T, *>

        return kProperty.get(instance)
    }

    fun <V> setValueByName(propName: String, instance: T, value: V) {
        val prop = getProperty(propName)

        if (prop == null)
            return

        if (prop !is KMutableProperty1<*, *>)
            return

        val mutableProp = prop as KMutableProperty1<T, V>
        mutableProp.set(instance, value)
    }

    fun <V> getValue(prop: KMutableProperty1<T, V>, instance: T): V {
       return prop.get(instance)
    }

    fun <V> setValue(prop: KMutableProperty1<T, V>, instance: T, value: V) {
        prop.set(instance, value)
    }

    fun callByName(functionName: String, vararg args: Any?): Any? {
        val function = getFunction(functionName)

        if (function == null)
            return null

        return function.call(*args)
    }

    fun call(function: KFunction<*>, vararg args: Any?): Any? {
        return function.call(*args)
    }

}

Create KClass and Reflection Class

val kclass = ImAClass::class
val util = Reflection(kclass)

Create instance

fun instance(): T {
    return kClass.createInstance()
}

//Usage
val instance = util.instance()
println("Instance: $instance")

Get properties

fun properties(): Collection<KProperty<*>> {
    return kClass.memberProperties
}

//Usage
val properties = util.properties()
properties.forEach { println("Property: $it") }

Get property by name

fun getProperty(propName: String): KProperty<*>? {
    return kClass
        .memberProperties
        .filter { it.name == propName }
        .firstOrNull()
}

//Usage
val prop = util.getProperty("property")
println("Property by name: $prop")

Get functions

fun functions(): Collection<KFunction<*>> {
    return kClass.functions
}

//Usage
val functions = util.functions()
functions.forEach { println("Function: $it") }

Get function by name

fun getFunction(functionName: String): KFunction<*>? {
    return kClass
        .functions
        .filter { it.name == functionName }
        .firstOrNull()
}

// Usage
val function = util.getFunction("function")
println("Function by name: $function")

Set property value by name

fun <V> setValueByName(propName: String, instance: T, value: V) {
    val prop = getProperty(propName)

    if (prop == null)
        return

    if (prop !is KMutableProperty1<*, *>)
        return

    val mutableProp = prop as KMutableProperty1<T, V>
    mutableProp.set(instance, value)
}

//Usage
util.setValueByName("property", instance, 1)
println("Set value by name: ${instance.property}")

Get Value with property name

fun getValueByName(propName: String, instance: T): Any? {
    val prop = getProperty(propName)

    if (prop == null)
        return null

    if (prop !is KProperty1<*, *>)
        return null

    val kProperty = prop as KProperty1<T, *>

    return kProperty.get(instance)
}

//Usage
val value = util.getValueByName("property", instance)
println("Get value by name: ${value}")

Set Value with property

fun <V> setValue(prop: KMutableProperty1<T, V>, instance: T, value: V) {
    prop.set(instance, value)
}

//Usage
util.setValue(ImAClass::property, instance, 2)
println("Set value with property ${instance.property}")

Get Value with property

fun <V> getValue(prop: KMutableProperty1<T, V>, instance: T): V {
   return prop.get(instance)
}

// Usage
val value1 = util.getValue(ImAClass::property, instance)
println("Get value with property $value1")

Call function by name

fun callByName(functionName: String, vararg args: Any?): Any? {
    val function = getFunction(functionName)

    if (function == null)
        return null

    return function.call(*args)
}

//Usage
val value2 = util.callByName("function",  instance, 2)
println("Call function, param: $value2")

Call with function

fun call(function: KFunction<*>, vararg args: Any?): Any? {
    return function.call(*args)
}

// Usage
val value3 = util.call(ImAClass::function, instance, 3)
println("Call function, param: $value3")

Github code: https://github.com/FractalCodeRicardo/kotlin-reflection-cheat-sheet

Leave a Reply

Your email address will not be published. Required fields are marked *