Kotlin invoke getter/setter reflectively

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.


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