Reflection in Kotlin

Reflection is the process of analyzing and modifying all the capabilities of the kotlin class at runtime. Reflection in kotlin is used to manipulate class and its members which include properties, functions, constructor, etc. at runtime.

    Reflection can be used for:
  • to Create instances of classes
  • lookup function and invoke them
  • inspect annotations
  • to find properties and discover parameter and generic

Manipulate Collections

Kotlin Reflection

There are two types of reflection is present in kotlin.

  • Java Reflection API : When you are using the Java libraries, they will use Java reflection classes. Java reflections are present under java.lang.reflect package
  • Kotlin Reflection API : Kotlin reflections are present in kotlin.reflect package

Features of Kotlin reflection

  • Gives access to properties and nullable types, which are not present in the Java
  • Kotlin reflection is not a replacement for Java reflection but the addition of features
  • You can use the kotlin reflection to access JVM code which was written by a languages

KClass in Kotlin Reflection

KClass is the entry point in Kotlin reflection, KClass represents a class in kotlin and it is a central type. To get an instance of the KClass for any type, we have to call special syntax along with which we want to use the reflection, the syntax is ::class.

val lang = "kotlin" val kclass :KClass<String> = lang::class

Instead of variable, we can get the KClass instanceKClass instance for a data type as well. val kclassDataType :KClass<String> = String::class

For a Classloader, there is going to be only one KClass Object for the given data type. If you try to instantiate KCLass multiple times still you would be receiving the same Object's reference, Kotlin will not create a new reference

Below three of the variables will have the same reference because they belong to String type and we can have only one KClass object for one datatype. val kclass :KClass<String> = "kotlin"::class val kclass1 :KClass<String> = "java"::class val kclass2 :KClass<String> = ""python"::class

We can get the object of the KClass in another way by using the fully qualified class name. The Fully qualified class name will have the packages and then the class name.

To use the fully qualified class name, we have to get the Class using the Java forName method like below.val kclass = Class.forName("com.sample.SampleClass").kotlin

forName() is present under the class called Class, and the forName() method is a static method, which is the Java reflection way of retrieving the hande of the class. With this handle, you can access all the things present in the class.

An object created for the KClass will include elements like Parameters, superclasses, functions, constructors, annotations, and properties.

KClass for Class Parameters :

We can get the class parameters using the typeParameters method present in the KClass. Int and String are the class parameters in below class. class Bucket<int, string="" style="box-sizing: inherit;">{ } fun main(args: Array<String>) { // create object for KClass using ::class val buckTypes = Bucket::class println(buckTypes.typeParameters) println("first value : "+buckTypes.typeParameters[0]) println("first value : "+buckTypes.typeParameters[1]) }</int,>

KClass for Class's Superclasses :

We can get the superclasses of a class in kotlin using the superclasses parameter in the KClass object, but it returns the names of the super class not handles of the superclasses.

import java.io.Serializable
import kotlin.reflect.full.superclasses
// super class is Serializable and Any by default
class Bucket:Serializable{
}
fun main(args: Array<String>) {
    // create object for KClass using ::class
    val buckTypes = Bucket::class
    println(buckTypes.superclasses)
}

KClass to get Parameters that a class accepts :

We can get the parameters of the using memberProperties property of KClass, which the class accepts as the primary constructor's parameters.

import kotlin.reflect.full.memberProperties
// super class is Serializable and Any by default
class Bucket(var a:String, var flag:Boolean){
}
fun main(args: Array<String>) {
    // create object for KClass using ::class
    val buckTypes = Bucket::class
    println(buckTypes.memberProperties)
}

KClass to get access functions of a class :

We can get the details of the member functions of a class using memberFunctions property present in kotlin's KClass. This method not only juts prints the functions in class but also the functions in the super class.

memberFunctions will not get the details of the extension function of the class.

import kotlin.reflect.full.memberFunctions
class Bucket{
    fun printSomething(){
        println("something")
    }
    fun printNothing(){
        println("")
    }
}
fun main(args: Array<String>) {
    // create object for KClass using ::class
    val buckTypes = Bucket::class
    println(buckTypes.memberFunctions)
}

KClass to get access extensions functions of a class :

We can get the details of the extension functions using the memberExtensionFunctions property of KClass.

import kotlin.reflect.full.memberExtensionFunctions
class Bucket{
    fun printSomething(){
        println("something")
    }
    fun printNothing(){
        println("")
    }
}
fun Bucket.IAmExtensionFunction(){
}
fun main(args: Array<String>) {
    // create object for KClass using ::class
    val buckTypes = Bucket::class
    println(buckTypes.memberExtensionFunctions)
}

KClass to get all the functions of a class :

Sometimes, you might want to get the details of the member function and extension function in the same place, in such cases you can use function property from the KClass.

import kotlin.reflect.full.functions
class Bucket{
    fun printSomething(){
        println("something")
    }
    fun printNothing(){
        println("")
    }
}
fun Bucket.IAmExtensionFunction(){
}
fun main(args: Array<String>) {
    // create object for KClass using ::class
    val buckTypes = Bucket::class
    println(buckTypes.functions)
}

Read Properties File in Kotlin

Constructors with reflection in kotlin

Sometimes, we might want to inspect the available list of all the constructors declared on a given type/Class by using the constructor's property available on the KClass type.

class Bucket(value: Int){
    constructor(amount:Int, color:String):this(amount){
        print("secondary constructor")
    }
    constructor(amount:Int, full:Boolean):this(amount){
        print("secondary constructor")
    }
    fun printSomething(){
        println("something")
    }
}
fun main(args: Array<String>) {
    var buck = Bucket::class
    var buckets = buck.constructors
    println(buckets)
}

Any & Unit & Nothing

KFunction in Kotlin Reflection

Kotlin reflection not only handles classes and objects but also KFunction class, call() function invokes the target function. call() function accepts variable number of arguments (varag)

KFunction instance itself is not tied to any particular instance/object, we need to provide the receiver/Object on which the function should be invoked on, instance/object is always the first argument to call.

You might need to provide the parameter that a function accepts from the second position onwards as the first position always should be the object/receiver.

import kotlin.reflect.full.functions
class Bucket{
    fun printSomething(name:String){
        println("something : $name")
    }
    fun printNothing(){
        println("Nothing")
    }
}
fun main(args: Array<String>) {
    // create object for KClass using ::class
    val buckTypes = Bucket::class
	var buck = Bucket()
    var functionToInvoke  = buckTypes.functions.find { it.name == "printNothing" }
    functionToInvoke?.call(buck)

	// invoke function that accepts a parameter
	var funInvoke  = buckTypes.functions.find { it.name == "printSomething" }
	funInvoke?.call(buck, "chercher tech")
}

I know, you might have this in your head: if I am providing the all the details like function name and then I have to provide the object of the class to invoke then Why I cannot invoke like below.

var buck = Bucket()
buck.printNothing()



Yes, you can invoke it, but consider this scenario: You have some file(excel/Properties), now you have to read the values from the files then you have to invoke a function, do you think the above code will help (code with direct class).

The answer is a big NO, we have no idea what function we are going to call so we have to use reflection in such places.

Elvis Operator [?:]

KProperty in Kotlin's Reflection

We can retrieve the value of a class member property using kotlin KProperty, With KProperty we might need to call the getter of the variable, which is get() function from the KProperty

We can get the value of the variable similar to the call of a function, using the call() function

import kotlin.reflect.full.memberProperties
class Bucket{
    var siteName:String = "chercher tech"
}
fun main(args: Array<String>) {
    // create object for KClass using ::class
    val buckTypes = Bucket::class
    var buck = Bucket()
    var variableToInvoke  = buckTypes.memberProperties.find { it.name == "siteName" }
    // using getter
	println(variableToInvoke?.get(buck))
	// using call()
    println(variableToInvoke?.call(buck))
}

Set variable value using KMutableProperty:

Setting a variable value is kind of not easy, all the variable we get through the memberProperties are immutable. You cannot change the value of the immutable object.

Because of this reason, you will not have the setter method in KProperty. To set value for any variable we have to smart cast the variable to KMutableProperty class in kotlin using the is keyword.

import kotlin.reflect.KMutableProperty
import kotlin.reflect.full.memberProperties
class Bucket{
    var siteName:String = "chercher tech"
    var authorName = "karthiq"
}
fun main(args: Array<String>) {
    // create object for KClass using ::class
    val buckTypes = Bucket::class
    var buck = Bucket()
    var variableToInvoke  = buckTypes.memberProperties.find { it.name == "siteName" }
    println(variableToInvoke?.get(buck))
    // is helps in smart casts
    if (variableToInvoke is KMutableProperty<*>) {
        variableToInvoke.setter.call(buck, "I am a changed value to siteName")
    }
    // retrive the value after change
    println(variableToInvoke?.get(buck))
}

Companion Objects

We can get a reference to objects or companion objects through reflection. You can get a reference to the companion object using the companionObject property defined on the KClass type

import kotlin.reflect.full.companionObject
class Bucket() {
    companion object {
        fun filling(){
            println("companion object is kind of static in kotlin")
        }
    }
}
fun main(args: Array<String>) {
    var buck = Bucket::class
    var bucketComp = buck.companionObject
    println(bucketComp)
}

Higher Order Functions

Instantiation/Object Creation using reflection

The most common uses of reflection are to create instances of types without knowing those types at compile time. We can create an instance/Object using createInstance function on a KClass reference. In the previous example, we were creating the object/instance explicitly, but in below example, we will be using the createInstance function to create the object.

import kotlin.reflect.full.createInstance
import kotlin.reflect.full.functions
class Bucket(value: Int = 0){
    fun printSomething(){
        println("something")
    }
    fun printNothing(){
        println("Nothing")
    }
}
fun main(args: Array<String>) {
    var buck = Bucket::class
    var bucketObject = buck.createInstance()
    buck.functions.find { it.name == "printSomething" }?.call(bucketObject)
}

The drawback with createInstance is that it will only work for classes with no parameters, or where all parameters are optional. A parameter is considered optional if it has a default value supplied.

Exceptions in kotlin

Comment / Suggestion Section
Point our Mistakes and Post Your Suggestions