Introduction to the reflection feature in Kotlin

In programming, reflection is a programming language’s ability to inspect and interact with statically defined classes, functions, and properties during runtime.

The feature is particularly useful when you receive an object instance of an unknown class.

By using reflection, you can check if a particular object has a certain method, and call that method when it exists.

To use reflection in Kotlin, you need to include the kotlin-reflect library in your project:

dependencies {
    implementation("org.jetbrains.kotlin:kotlin-reflect:1.6.10")
}

The library contains the runtime component required for using Kotlin reflection features.

Next, let’s see how you can get class, function, and property references using Kotlin reflection feature.

Kotlin reflection - class reference

Suppose you have a Dog class with the following definitions:

class Dog(var name: String) {
    fun bark() {
        println("Bark!")
    }

    fun bark(sound: String) {
        println(sound)
    }

    private fun hello() {
        println("Hello! My name is $name")
    }
}

To get the class reference in Kotlin, you can use the class literal syntax ::class as shown below:

val classRef = Dog::class

Alternatively, you can get the class reference from an object instance by using the same ::class syntax on the instance:

val myDog = Dog("Puppy")

val classRef = myDog::class

Getting the class reference from an object is also known as a bounded class reference.

Once you have the class reference, you can access the properties of the reference to find out more about that class.

For example, you can find the name of the class and check if that class is a data class:

println(classRef.simpleName) // Dog
println(classRef.qualifiedName) // org.metapx.Dog
println(classRef.isData) // false

In Kotlin, the class reference is identified as the Kclass type which stands for Kotlin class.

You can check the Kclass documentation for all properties and methods you can access to find out about the class from its reference.

Aside from inspecting the class, the Kclass also has some interesting abilities. The createInstance() method, for example, allows you to create a new object from the class reference:

val secondDog = classRef.createInstance()

But keep in mind that the createInstance() method only works when the class has a constructor with optional or no parameter.

An error will be thrown when no constructor fulfills the criteria.

Accessing Kotlin class reference methods

You can also get access to the methods of the class reference regardless of their access modifier.

This means even private functions of a class can be accessed from its reference.

The memberFunctions property of Kclass stores all methods of the class as a Collection:

val myDog = Dog("Puppy")

val classRef = myDog::class

classRef.memberFunctions.forEach { 
    println(it.name) 
}

The output will be as follows:

bark
bark
hello
equals
hashCode
toString

Next, you can call the class function from its reference as follows:

val myDog = Dog("Puppy")

val classRef = myDog::class

val barkRef = classRef.memberFunctions.find { 
    it.name == "bark" 
}

barkRef?.call(myDog)

First, you need to use the find() function to retrieve the function reference.

Then, check if the function reference is found using the null-safe call.

When the reference is found, use the call() method from the function reference Kfunction type.

The first argument of the call() method must be an instance of the class reference, which is why myDog object is passed into the method.

When your function is private, you need to change the isAccessible property of the function reference as true first before calling the function:

val helloRef = classRef.memberFunctions.find { 
    it.name == "hello" 
}

helloRef?.isAccessible = true

helloRef?.call(myDog)

And that’s how you access the methods of a class using its reference.

Accessing Kotlin class reference properties

The properties of a Kotlin class reference can be accessed the same way you access its methods.

The properties of a class are stored in memberProperties as a Collection.

For example, you can get the name property value of the myDog instance as follows:

val myDog = Dog("Puppy")

val classRef = myDog::class

val nameRef = classRef.memberProperties.find {
    it.name == "name" 
}

println(nameRef?.getter?.call(myDog)) // Puppy

A property reference is an instance of KProperty type. The value of the property is retrieved by calling the getter() method.

To change the value of the name property, you need to cast the property into KMutableProperty first as shown below:

val myDog = Dog("Puppy")

val classRef = myDog::class

val nameRef = classRef.memberProperties.find {
    it.name == "name" 
} as KMutableProperty<*>?

nameRef?.setter?.call(myDog, "Jacob")

println(myDog.name) // Jacob

The KMutableProperty holds the setter() method, which you need to call to set the value of the property.

Now you’ve learned how to access methods and properties from a class reference.

Next, let’s look at how you can get a function reference with Kotlin reflection

Kotlin reflection - function reference

You can get a reference to a named Kotlin function by using the :: operator.

Here’s an example:

fun hello() {
    println("Hello World!")
}

val funRef = ::hello

funRef() // Hello World!

The funRef above will be an instance of Kfunction type, which represents a function with introspection capabilities.

Conclusion

Now you’ve learned what the Kotlin reflection feature is and how it works with some examples. Reflection is a powerful feature that’s only used for specific requirements.

Because of its ability to find inspect a source code, it’s frequently used when developing a framework or library for further development.

JUnit and Spring frameworks are notable for using reflection in their source code.

The library author won’t know the classes and functions created by the user. Reflection allows the framework to deal with classes and functions without knowing about them in advance.

Take your skills to the next level ⚡️

I'm sending out an occasional email with the latest tutorials on programming, web development, and statistics. Drop your email in the box below and I'll send new stuff straight into your inbox!

No spam. Unsubscribe anytime.