Instead of using Java fields and Java reflection code, you can also use Kotlin properties and Kotlin reflection classes:
class Reflector {
val Foo = 1;
fun printFields() {
this::class.memberProperties.forEach {
if (it.visibility == KVisibility.PUBLIC) {
println(it.name)
println(it.getter.call(this))
}
}
}
}
Answer from BladeCoder on Stack OverflowInstead of using Java fields and Java reflection code, you can also use Kotlin properties and Kotlin reflection classes:
class Reflector {
val Foo = 1;
fun printFields() {
this::class.memberProperties.forEach {
if (it.visibility == KVisibility.PUBLIC) {
println(it.name)
println(it.getter.call(this))
}
}
}
}
It seems that you are passing the Field variable it as a parameter getInt whereas the parameter should be the object the field belongs to this:
From the Javadoc for Field.getInt(Object obj):
obj - the object to extract the int value from
Perhaps this is what you meant to do:
class Reflector {
@JvmField val Foo = 1;
fun printFields() {
this.javaClass.fields.forEach {
println(it.isAccessible)
println(it.getInt(this))
}
}
}
fun main(args : Array<String>) {
Reflector().printFields()
}
jvm - kotlin reflection get list of fields - Stack Overflow
java - Kotlin reflection - getting all field names of a Class - Stack Overflow
(Reflections) Get list of fields?
How to change a kotlin private val using reflection? - Stack Overflow
Did you want fields as-in "backing field" or fields as in "properties" ... Kotlin really only has properties. You can get these for some class using:
MyTest::class.memberProperties
// or
MyTest::class.declaredMemberProperties
And from a Java Class<T>, use the kotlin extension property to get the Kotlin KClass<T> from which you can proceed:
someClassOfMine.javaClass.kotlin.memberProperties
This requires the kotlin-reflect dependency as well to be added to your build and classpath. You'll find many other useful things on KClass
For the secret backing fields behind a property, use Java reflection at your own risk.
Very easy now with Kotlin v1.1, You can use the following method to get the fields in kotlin
val fields = MyClass.javaClass.kotlin.members
Where MyClass is the class of your choice.
In order to use this you need to have kotlin-reflect included in your gradle build file as below
compile "org.jetbrains.kotlin:kotlin-reflect:$kotlin_version"
Additionally, it is also possible to get the fields from the javaClass directly if you need java fields (useful in some cases as these cover a slightly different scope)
val fields = MyClass.javaClass.declaredFields
Probably what you want is to get properties of a class, not fields. This can be done as follows:
MyClass::class.declaredMemberProperties
Getting fields is also possible through Java reflection:
MyClass::class.java.declaredFields
But fields are rather an implementation detail in Kotlin, because some properties might have no backing field.
As to the visibility, for properties you can check the getter visibility modifiers:
val p = MyClass::class.declaredMemberProperties.first()
val modifiers = p.javaGetter?.modifiers
Note: it's null in case of a simple private val or @JvmField usage. Then you can inspect p.javaField instead.
Then, if modifiers is not null, just check it with Modifier.isPrivate(...).
Properties in Kotlin can have separate visibility modifiers for getter and setter, but a setter access cannot be more permissive than that of the getter, which is effectively the property visibility.
There is indeed documentation available for Kotlin reflection: an overall summary of reflection and the API docs including for the KClass.members function. You can also jump to the declaration of that method and you will see it is documented in the source code as well.
Hey,
is there an equivalent for the java reflection foo.getClass().getFields() in Kotlin? I could only find that I can access a field when I know it's name, but I would like to handle fields in a generic way.
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.
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*******