Reflection


What is 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
  • look up function and invoke them
  • inspect annotations
  • to find properties and discover parameter and generic
It is always better not to use reflection if a have other way to solve the problem

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 replacement for Java reflection but an addition o features
  • You can use the kotlin reflection to access JVm code which was written by an languages

KClass in Kotlin Reflection

KClass is entry point in Kotlin reflection, KClass represents a class in kotlin and it is a central type. To get instance of the KClass for any type , we have to call special syntax along with which we want to use the reflection, 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 Class loader, there is going to be only one KClass Object for given data type. If you try to instantiate KCLass multiple times still you would be receives the same Object's reference, Kotlin will not create a new reference

Below three of the variables will have same reference, because they belong to String type and we can have only one KClass object for one data Type. 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. Fully qualified class name will have the packages and then class name.

To use 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 class called Class, and the forName() method is static method, which is Java reflection way of retrieving the hande of the class. With this hanld eyou can access all the things present in the class.

Object created for the KClass will include the elements like Parameters, super classes, 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{ } 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]) }

KClass for Class's Super classes :

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


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 the parameters of the using memberProperties property of KClass, which the class accepts as the primary constructors 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 functions of a class :

Sometimes, you might want to get the details of the member function and extension function in 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 constructors on a type. May be we need to create a type that has a constructor that requires values.

Or perhaps we want to determine which fields are needed to create an instance of a type at runtime. Or, similarly, perhaps we want to see if a class can be created from the parameters we have available.

We can get a list of all the constructors declared on a given type/Class by using the constructors 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 functions and properties . Most of the Kotlin system can be accessed, and that includes functions and properties.

There is no use of just getting the names of the function present in kotlin class, the actual use of the reflection is the ability to invoke the function .

There is the function called class() present inside the 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 second position onwards as 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 ave to invoke a functions, do you think the above code will help (code with direct class).

Answer is big NO, we have no idea what function that 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 th 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))
}

Top Level Functions

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

Most common uses of reflection is to create instances of types without knowing those types at compile time. We can create a instance/Object using createInstance function on a KClass reference. In 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

aaaaaaaaaaaaa
Comment / Suggestion Section
Point our Mistakes and Post Your Suggestions

Recent Addition

new tutorial Selenium Online Training : Our next online training course for Selenium with Java starts from 17th December 2018.

You can attend first 3 classes for free, the total course fee is INR 10,000

The course time would be 8.00 PM(IST) for the first three classes

If you are interested to learn, then you can join the course by sending email to chercher.tech@gmail.com

or Register below


 
Join My Facebook Group
Join Group