You can use Kotlin reflection, which requires you to add kotlin-reflect as a dependency to your project.

Here you can find kotlin-reflect for Kotlin 1.0.5, or pick another version if you use different Kotlin version.

After that, you can rewrite your code as follows:

val properties = myObject.javaClass.kotlin.memberProperties
for (p in properties.filterIsInstance<KMutableProperty<*>>()) {
    val data = when (p.returnType.javaType) {
        Int::class.javaPrimitiveType,
        Int::class.javaObjectType -> foo
        Double::class.javaPrimitiveType,
        Double::class.javaObjectType -> bar
        String::class.java -> baz
        else -> null
    }
    if (data != null)
        p.setter.call(myObject, data)
}

Some details:

  • Despite using Kotlin reflection, this approach works with Java classes as well, their fields and accessors will be seen as properties, as described here.

  • Just like with Java reflection, memberProperties returns public properties of this type and all its supertypes. To get all the properties declared in the type (including the private ones, but not those from the supertypes), use declaredMemberProperties instead.

  • .filterIsInstance<KMutableProperty<*> returns only the mutable properties, so that you can use their p.setter later. If you need to iterate over the getters of all the properties, remove it.

  • In the when block, I compared p.returnType.javaType to Int::class.javaPrimitiveType and Int::class.javaObjectType, because what's Int in Kotlin can be mapped to either Java int or java.lang.Integer depending on its usage. In Kotlin 1.1, it will be enough to check p.returnType.classifier == Int::class.

Answer from hotkey on Stack Overflow
Top answer
1 of 2
19

You can use Kotlin reflection, which requires you to add kotlin-reflect as a dependency to your project.

Here you can find kotlin-reflect for Kotlin 1.0.5, or pick another version if you use different Kotlin version.

After that, you can rewrite your code as follows:

val properties = myObject.javaClass.kotlin.memberProperties
for (p in properties.filterIsInstance<KMutableProperty<*>>()) {
    val data = when (p.returnType.javaType) {
        Int::class.javaPrimitiveType,
        Int::class.javaObjectType -> foo
        Double::class.javaPrimitiveType,
        Double::class.javaObjectType -> bar
        String::class.java -> baz
        else -> null
    }
    if (data != null)
        p.setter.call(myObject, data)
}

Some details:

  • Despite using Kotlin reflection, this approach works with Java classes as well, their fields and accessors will be seen as properties, as described here.

  • Just like with Java reflection, memberProperties returns public properties of this type and all its supertypes. To get all the properties declared in the type (including the private ones, but not those from the supertypes), use declaredMemberProperties instead.

  • .filterIsInstance<KMutableProperty<*> returns only the mutable properties, so that you can use their p.setter later. If you need to iterate over the getters of all the properties, remove it.

  • In the when block, I compared p.returnType.javaType to Int::class.javaPrimitiveType and Int::class.javaObjectType, because what's Int in Kotlin can be mapped to either Java int or java.lang.Integer depending on its usage. In Kotlin 1.1, it will be enough to check p.returnType.classifier == Int::class.

2 of 2
2

If You need to get property getter/setter, there is a couple of built-in constructions for it YourClass::propertyName

have a look at example bellow

fun main(args: Array<String>) {
        val myObject = Cat("Tom", 3, 35)
        println(Cat::age.getter.call(myObject)) // will print 3
        Cat::age.setter.call(myObject, 45)
        print(myObject) // will print Cat(name=Tom, age=45, height=35)
    }

    data class Cat(var name : String, var age : Int, val height : Int)

but sometimes you don't know class exactly(working with generics) or need to get list of properties, then use val <T : Any> KClass<T>.declaredMemberProperties: Collection<KProperty1<T, *>> it will return all properties, some of them can be mutable(var) and some immutable(val), you can find out immutability by checking belonging to KMutableProperty<*> (by filtering with is operator or using convenience methods such as filterIsInstance<KMutableProperty<*>>)

about your code snippet

I absolutely agree with hotkey, but now it is better to use myObject::class.declaredMemberProperties instead of myObject.javaClass.kotlin.memberProperties

because the second one is deprecated

https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.jvm/java-class.html

     data class Cat(var name : String, var age : Int, val height : Int)

     @JvmStatic
            fun main(args: Array<String>) {
                val myObject = Cat("Tom", 3, 35)
                val properties = myObject::class.declaredMemberProperties
                for (p in properties.filterIsInstance<KMutableProperty<*>>()) {
                    val data = when (p.returnType.javaType) {
                        Int::class.javaPrimitiveType,
                        Int::class.javaObjectType -> 5
                        String::class.java -> "Rob"
                        else -> null
                    }
                    if (data != null)
                        p.setter.call(myObject, data)
                }
                println(myObject)
                // it will print Cat(name=Rob, age=5, height=35),
                // because height isn't var(immutable)
            }

in general, I would approach similar problems with such construction in mind

val myObject = Cat("Tom", 3, 35)

Cat::class.declaredMemberProperties
                    //if we want only public ones
                    .filter{ it.visibility == KVisibility.PUBLIC }
                    // We only want strings
                    .filter{ it.returnType.isSubtypeOf(String::class.starProjectedType) }
                    .filterIsInstance<KMutableProperty<*>>()
                    .forEach { prop ->
                        prop.setter.call(myObject, "Rob")
                    }

println(myObject)
//it will print Cat(name=Rob, age=3, height=35),
//because name is only eligible in this case
🌐
Kotlin
kotlinlang.org › api › latest › jvm › stdlib › kotlin.reflect › -k-mutable-property
KMutableProperty - Kotlin Programming Language
September 22, 2022 - kotlin-stdlib / kotlin.reflect ... a property declared as a var. JVM · 1.0 · Setter of the property is a set method declared alongside the property....
🌐
Kotlin
kotlinlang.org › api › latest › jvm › stdlib › kotlin.reflect › -k-mutable-property › -setter.html
Setter - Kotlin Programming Language
kotlin-stdlib / kotlin.reflect / KMutableProperty / Setter · JVM · 1.0 · interface Setter<V> : KProperty.Accessor<V>, KFunction<Unit> (source) Setter of the property is a set method declared alongside the property.
🌐
Kotlin Discussions
discuss.kotlinlang.org › support
Reflection and properties, checking for custom getters/setters - Support - Kotlin Discussions
July 20, 2021 - Hi all, So I’m using reflection to scrape classes for annotated properties, which I then use to inject automatically loaded resources. This seems to be working well, but I have a question about getters and setters in th…
Top answer
1 of 3
27

KClass has an objectInstance field:

Class.forName(ownerClassName).kotlin.objectInstance

This is built into Kotlin reflection.

Returns: The instance of the object declaration, or null if this class is not an object declaration.

This would be even nicer if KClass had a forName method, but sadly it does not (yet), so we need to instead get the (Java) Class and convert it to KClass.

You can get a KClass instance from a Class by using the .kotlin extension property.

Then you can continue with the rest of your code. I converted this to Kotlin's reflection library:

val kClass = Class.forName(ownerClassName).kotlin
// Get the object OR a new instance if it doesn't exist
val instance = kClass.objectInstance ?: kClass.java.newInstance()

val member = kClass.memberProperties
// Has to be a mutable property, otherwise we can't set it
        .filterIsInstance<KMutableProperty<*>>()
// Check the name
        .filter { it.name == fieldName }
        .firstOrNull()

// Set the property
member?.setter?.call(instance, value)

Here is a working test:

object TestObject {
    var field = 3
}

fun setValue(ownerClassName: String, fieldName: String, value: Any) {
    val kClass = Class.forName(ownerClassName).kotlin
    val instance = kClass.objectInstance ?: kClass.java.newInstance()

    val member = kClass.memberProperties.filterIsInstance<KMutableProperty<*>>()
            .firstOrNull { it.name == fieldName }

    member?.setter?.call(instance, value)
}

fun main(args: Array<String>) {
    println(TestObject.field) // 3
    setValue("some.package.TestObject", "field", 4)
    println(TestObject.field) // 4
}
2 of 3
13

object is translated into a class with a private constructor and a static field called INSTANCE where the only instance is stored when this class is loaded, so replacing Class.forName(ownerClassName).newInstance() with

Class.forName(ownerClassName).getDeclaredField("INSTANCE").get(null)

should work.


Javadoc:

  • Class#forName
  • Class#getDeclaredField
  • Field#get
🌐
Kotlin
kotlinlang.org › api › latest › jvm › stdlib › kotlin.reflect.jvm › java-setter.html
javaSetter - Kotlin Programming Language
(source) Returns a Java Method instance corresponding to the setter of the given mutable property, or null if the property has no setter, for example in case of a simple private var in a class.
🌐
Baeldung
baeldung.com › home › kotlin › kotlin classes and objects › reflection with kotlin
Reflection with Kotlin | Baeldung on Kotlin
March 19, 2024 - This looks exactly the same as in Java 8 to obtain a method reference, and we can use it in exactly the same way. However, in Kotlin this method reference can also be used to get reflection information about the target.
Find elsewhere
🌐
Medium
medium.com › @pranamsharma.1997 › what-is-reflection-in-kotin-41e05e94a3ae
What is Reflection in kotlin ? Kotlin Reflection: A Comprehensive Guide to Inspect, Modify, and Create Objects at Runtime | by Pranam Sharma | Medium
May 11, 2023 - In this example, `MyClass` is a class with a single property called `myProperty`. We create an instance of the class and set the value of the property to 1. We then obtain a reference to the `KMutableProperty` object that represents the property using the `::` operator and the name of the property. Finally, we use the `setter` property of the `KMutableProperty` object to set the value of the property to 2. Another powerful feature of reflection is the ability to create new objects at runtime.
🌐
GitHub
github.com › JetBrains › kotlin › blob › master › core › reflection.jvm › src › kotlin › reflect › jvm › internal › KPropertyImpl.kt
kotlin/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KPropertyImpl.kt at master · JetBrains/kotlin
July 3, 2018 - is KotlinProperty -> { val accessorSignature = jvmSignature.signature.run { when { isGetter -> if (hasGetter()) getter else null · else -> if (hasSetter()) setter else null · } } ·
Author   JetBrains
🌐
Kotlin
kotlinlang.org › docs › properties.html
Properties | Kotlin Documentation
This example uses reflection to show which annotations are present on the getter and setter. In Kotlin, accessors use backing fields to store the property's value in memory.
🌐
Kotlin Discussions
discuss.kotlinlang.org › support
Kotlin and Reflection - Support - Kotlin Discussions
April 3, 2016 - Suppose that I have the following ... l = ReflectionQuestion() val result = ReflectionQuestion::class.memberProperties.find { it.name == "name" } if (result is KMutableProperty1) { result.setter.isAccessible = true result.set(l, "Kotlin") // error } } The......
Top answer
1 of 2
41

Answer

In short, you have to use Java reflection APIs in this case, and here is how to do it:

fun main() {
    val mainClass = MainClass()
    val f = MainClass::class.java.getDeclaredField("info")
    f.isAccessible = true
    f.set(mainClass, "set from reflection")
    mainClass.printInfo() // Prints "set from reflection"
}

class MainClass {
    private val info: String = "Hello"
    fun printInfo() = println(info)
}

Reason for using Java reflection APIs

It is not possible to do with Kotlin reflection APIs since no setter code is generated for a read-only (val) property. So to change it, we need to use Java reflection APIs which is more low-level. First, we use Tools -> Kotlin -> Show Kotlin Bytecode to see what the generated bytecode looks like. Then we see this:

// ================MainClass.class =================
// class version 50.0 (50)
// access flags 0x31
public final class MainClass {
  // access flags 0x12
  private final Ljava/lang/String; info = "Hello"
  // ...

i.e that the info fields in the MainClass Kotlin class causes the compiler to emit JVM code for a regular MainClass Java class with a final String info field. So to change it, we can use Java reflection APIs, as in the code above.

Kotlin reflection API attempt

If the field would have been private var you would be able to Use Kotlin reflection APIs like this:

f?.let {
    val mutableProp = it as KMutableProperty<*>
    it.isAccessible = true
    mutableProp.setter.call(mainClass, "set from Kotlin reflection")
    val w = it.get(mainClass) as String
    println(w)
}

but if you try this with private val you will get the below exception

Exception in thread "main" java.lang.ClassCastException: class kotlin.reflect.jvm.internal.KProperty1Impl cannot be cast to class kotlin.reflect.KMutableProperty (kotlin.reflect.jvm.internal.KProperty1Impl and kotlin.reflect.KMutableProperty are in unnamed module of loader 'app')
    at MainKt.main(main.kt:107)
    at MainKt.main(main.kt)

since no setter code is generated for val fields, and thus the info property will have a Kotlin Reflection API type of KProperty and not KMutableProperty.

2 of 2
-2

This is working solution

import kotlin.reflect.KMutableProperty
import kotlin.reflect.full.memberProperties

class MySolution {

var name = ""
var email = ""
}

@Suppress("UNCHECKED_CAST")
fun main() {

//Dummy Result Set
val rs = mapOf<String,String>("name" to "My Name", "email" to "My Email")

val mySol = MySolution();
val xyzMp = MySolution::class.memberProperties;
xyzMp.forEach { mp ->
   val prop =  mp as KMutableProperty<String>
    prop.setter.call(mySol, rs[mp.name])
}

println(mySol.name)
println(mySol.email)
println("*****Enjoy*******")

output

My Name
My Email
**** *Enjoy*******
Top answer
1 of 3
5

object is not an instance of declaring class

Just as in Java, you need to pass the object itself as the first parameter when calling reflective methods.

The first parameter to call should be the companion object, as that is the object whose property you are trying to modify.

You are passing the companion's class object instead of the companion object itself.

A companion object is accessible either via ClassName.Companion, or when using further reflection, through KClass#companionObjectInstance.

companionProp.setter.call(WithProperty.Companion, "hello")
companionProp.setter.call(obj::class.companionObjectInstance, "hello")
companionProp.setter.call(WithProperty::class.companionObjectInstance, "hello")

When run, both variants print hello world as intended.

Keep in mind that Foo.Companion will result in a compile error if the companion object does not exist while the reflective variant will return null instead.

2 of 3
4

You can solve the same problem using java reflection.

Companion class:

class Example {
    companion object {
        val EXAMPLE_VALUE = "initial"
    }
}

Update a property using java reflection:

val field = Example::class.java.getDeclaredField("EXAMPLE_VALUE")
field.isAccessible = true
field.set(null, "replaced")

Tested with Kotlin 1.5.30 on Android 12:

Log.d("test-companion", Example.EXAMPLE_VALUE) // outputs "replaced"

WARNING: I'm not sure if java reflection is reliable for this case. It assumes some implementation details of Kotlin complier which could change in a future version. But the solution should be fine for a quick workaround. I used it to verify a bug fix on customer side before the next release of my library.

🌐
DevTut
devtut.github.io › kotlin › reflection.html
Kotlin - Reflection
val instance = TestClass() ... prop.setter.call(instance, "Our Value") } Reflection is a mechanism to introspect language constructs (classes and functions) at the runtime....
🌐
Kotlin Discussions
discuss.kotlinlang.org › t › exposing-legacy-getter-setter-as-kotlin-property › 12008
Exposing legacy getter/setter as Kotlin property - Kotlin Discussions
March 18, 2019 - Suppose I have a legacy Java class like this: public class MyClass { private String text; public String getText() { return this.text; } public void setText(String text) { this.text = text; } } Now in Kotlin I can do this: val obj = MyClass() obj.text = "something" And this .text gets resolved to the underlying setting (and getter).
🌐
Kotlin
kotlinlang.org › api › core › kotlin-reflect › kotlin.reflect.jvm
kotlin.reflect.jvm | Core API – Kotlin Programming Language
Returns a Java Method instance corresponding to the given Kotlin function, or null if this function is a constructor or cannot be represented by a Java Method. ... Returns a Java Method instance corresponding to the setter of the given mutable ...
🌐
DhiWise
dhiwise.com › post › a-beginners-guide-to-understanding-kotlin-reflection
A Beginner's Guide to Understanding Kotlin Reflection
September 27, 2024 - In this example, we first import kotlin reflection libraries and then use String::class to obtain a kotlin class reference. Similarly, we use ::sampleFunction to create a function reference and call it dynamically using the call method. This is a simple demonstration of how Kotlin reflection works in a functional style. • KClass: Represents a Kotlin class.
🌐
Medium
medium.com › @ramadan123sayed › kotlin-reflection-a-comprehensive-guide-f00417f2f521
Kotlin Reflection: A Comprehensive Guide | by Ramadan Sayed | Medium
August 12, 2024 - In this article, we’ll explore Kotlin reflection in depth, covering its basics, use cases, and practical examples, with a focus on how to leverage this feature effectively in real-world applications, including its common uses in Android development.