How can I read the value of property in a Kotlin data class instance if the property name is only known at runtime?
-
Kotlin has a reflection library: https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.reflect/-k-class/index.html – JB Nizet Feb 20 '16 at 15:44
4 Answers
Here is a function to read a property from an instance of a class given the property name (throws exception if property not found, but you can change that behaviour):
import kotlin.reflect.KProperty1
import kotlin.reflect.full.memberProperties
@Suppress("UNCHECKED_CAST")
fun <R> readInstanceProperty(instance: Any, propertyName: String): R {
val property = instance::class.members
// don't cast here to <Any, R>, it would succeed silently
.first { it.name == propertyName } as KProperty1<Any, *>
// force a invalid cast exception if incorrect type here
return property.get(instance) as R
}
build.gradle.kts
dependencies {
implementation(kotlin("reflect"))
}
Using
// some data class
data class MyData(val name: String, val age: Int)
val sample = MyData("Fred", 33)
// and reading property "name" from an instance...
val name: String = readInstanceProperty(sample, "name")
// and reading property "age" placing the type on the function call...
val age = readInstanceProperty<Int>(sample, "age")
println(name) // Fred
println(age) // 33

- 84,842
- 38
- 184
- 227
-
3I know this answer is almost 2 years old... is this still the way to do it? I'm curious if there is anything new that may have been added to the Kotlin API that would have created another way to achieve this. – Hatem Jaber Jan 08 '18 at 19:20
-
@HatemJaber If you are reading a property where you do not know the name at compile time, then yes. If you want to read a known property that is there at compile time you can use a property reference to access the property. – Jayson Minard Jan 27 '18 at 14:10
-
3@HatemJaber: newer versions of the reflection library allow for `instance::class.members` instead of `instance.javaClass.kotlin.declaredMemberProperties, though you should check that the type of the property is a `KProperty<*, *>` or `KMutableProperty<*, *>`. – outis Jul 13 '18 at 23:29
-
@AdamKis My answer still worked if a correct import statement was added, I have updated it to a newer version and included the imports. – Jayson Minard May 15 '19 at 20:12
-
@outis you don't need to check that because they all descend from `KProperty1
` as the above example was changed to handle. – Jayson Minard May 16 '19 at 19:52 -
If the instance class contains field of type List, it raises an Exception `IllegalAccessException: class kotlin.reflect.jvm.internal.calls.CallerImpl$FieldGetter cannot access a member of class java.util.Collections$SingletonList (in module java.base) with modifiers "private final"`. Is there a way to bypass this? – KeNVin Favo Oct 27 '21 at 14:22
-
If anyone is facing issues with **release build** (`Exception:java.lang.IllegalAccessException`) , try this https://stackoverflow.com/a/48159066/7710739 – Reejesh PK May 02 '22 at 06:57
You can do it through reflection, and it's all the same for data classes and normal ones.
The first option is just to use Java reflection:
val name = obj.javaClass
.getMethod("getName") // to get property called `name`
.invoke(obj)
You can even make an extension function:
inline fun <reified T : Any> Any.getThroughReflection(propertyName: String): T? {
val getterName = "get" + propertyName.capitalize()
return try {
javaClass.getMethod(getterName).invoke(this) as? T
} catch (e: NoSuchMethodException) {
null
}
}
It calls the public getter. To get a value of a private property you can modify this code using getDeclaredMethod
and setAccessible
. This will also work for Java objects with the corresponding getters (but it misses the convention of is
and has
getters for boolean
).
And usage:
data class Person(val name: String, val employed: Boolean)
val p = Person("Jane", true)
val name = p.getThroughReflection<String>("name")
val employed = p.getThroughReflection<Boolean>("employed")
println("$name - $employed") // Jane - true
The second option involves using
kotlin-reflect
library which you should add to your project separately, here's its documentation. It will let you get actual Kotlin property value, ignoring Java getters.
You can use javaClass.kotlin
to get actual Kotlin class token, and then you get a property from it:
val name = p.javaClass.kotlin.memberProperties.first { it.name == "name" }.get(p)
This solution will work only for Kotlin classes, not for Java ones, but it is much more reliable if you need to work with Kotlin classes: it doesn't depend on the underlying implementation.
-
The first solution has several flows: it excludes inherited properties, doesn't work with boolean properties (whose getter starts with is...), tries to access properties even if they're not public. Using the java.beans classes (or any Java library allowing to access bean properties) might be a better idea. – JB Nizet Feb 20 '16 at 16:29
-
-
@JBNizet, hmm, tried it just now -- Kotlin generates `getSomething` named methods even for `Boolean` properties, not `isSomething`. – hotkey Feb 20 '16 at 17:00
-
2That's part of my point: instead of assuming and relying on low-level methods, you'd better be relying of Kotlin reflection support for properties (i.e. the second part of the answer) or on higher-level Java abstractions dealing with Java Beans. – JB Nizet Feb 20 '16 at 17:32
-
The answers above didn't work for me so I've created an extension function for this:
@Throws(IllegalAccessException::class, ClassCastException::class)
inline fun <reified T> Any.getField(fieldName: String): T? {
this::class.memberProperties.forEach { kCallable ->
if (fieldName == kCallable.name) {
return kCallable.getter.call(this) as T?
}
}
return null
}
This is an example call:
val valueNeeded: String? = yourObject.getField<String>("exampleFieldName")
Also include this in your app's build.gradle:
implementation "org.jetbrains.kotlin:kotlin-reflect:$kotlin_version"

- 1,404
- 14
- 17
-
Kotlin team is trying to distance the language from checked exceptions, I believe. https://kotlinlang.org/docs/reference/exceptions.html#checked-exceptions – Farid Oct 07 '19 at 07:39
-
2
-
@Farid Yes, in Kotlin, we don't even have the option to declare "... throws IllegalAccessException", but it can be useful to indicate what type of exceptions can be expected from the method, hence the Throws annotation – Adam Kis Feb 16 '22 at 14:17
-
1
I wonder if it is possible to define the type of the field programmatically. You can get the type easily with:
kCallable.returnType
However you still have to assign the generic type explicitely:
getField<String>
instead of
getField<kCallable.returnType>
Edit: I ended up using the following:
when (prop.call(object)) {
is ObservableList<*> -> {}
is Property<*> -> {}
}

- 41
- 4
-
Did you find an answer to this? That's exactly what i'm dealing with right now. – melis Oct 29 '20 at 21:32