fwilhe
fwilhe

Reputation: 321

kotlin reflection get list of fields

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.

Upvotes: 32

Views: 46636

Answers (9)

Miguel Gamboa
Miguel Gamboa

Reputation: 9373

Regarding your example with a foo variable you may get its backing fields through:

val fields: List<Field?> = foo::class.memberProperties.map { it.javaField }

Upvotes: 0

mokpi
mokpi

Reputation: 158

We can use memberProperties.

Example:

class Color {
    val name: String
    val red: Int
    val green: Int
    val blue: Int
}

// ...

Color::class.memberProperties.size // returns 4

Upvotes: 0

tfad334
tfad334

Reputation: 598

If you want the properties in the order they are declared using Kotlin-reflect: MyClass::class.primaryConstructor.parameters

Upvotes: 1

Viks
Viks

Reputation: 1574

Simple answer

In you build.gradle (app) file

implementation("org.jetbrains.kotlin:kotlin-reflect:$kotlin_version")

And then

val fields = YourClass::class.declaredMemberProperties
for (i in fields){
    Log.e("Fields ===", i.name)
}

Cheers!!!

Upvotes: 3

WilliaGuy
WilliaGuy

Reputation: 207

like this:

  User::class.memberProperties.forEach { member ->
        log.i("${member.name} -> ${member.get(this)}")
    }

It works very well

Upvotes: -1

Paulo Buchsbaum
Paulo Buchsbaum

Reputation: 2659

There is a method in Kotlin that works without having to add a new dependency in a project:

Suppose a custom class called Mine

class Mine(var prop:String) {
    fun myMethod():Boolean {
        return true
    }
}

A new user function called isMethod

fun isMethod(t:Any, s:String):Boolean {
try  {
    t.javaClass.getMethod(s)   // or t::class.java.getMethod(s)
    return true
  } catch(e:Exception)  {
    return false
  }    
}

After one declares an Mine instance and test it.

fun main() {
  var m = Mine("Paulo")  
  println(isMethod(m, "myMethod"))  // it prints true
  println(isMethod(m, "otherMethod"))  // it prints false
}

Upvotes: 2

arkoak
arkoak

Reputation: 2497

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

Upvotes: 5

Jayson Minard
Jayson Minard

Reputation: 85946

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.

Upvotes: 24

Leonidos
Leonidos

Reputation: 10518

You can't do this in Kotlin, but there is a dirty unreliable way to do this in java. You can use java reflection. Like this:

public class TestClass {

    trait EmptyTrait
    class EmptyClass

    public var anotherVar:Int? = null
    public val contant:Float = 10f
    private var emptyTrait:EmptyTrait? = null
    val emptyClass:EmptyClass = EmptyClass()

    public fun setVal(fieldName: String, value: Int) {
        javaClass.getDeclaredField(fieldName).set(this, value);
    }

    public fun getFieldNames(): String {
        return javaClass.getDeclaredFields().map{it.getName()}.join(", ")
    }    
}

Let's test it:

val t = TestClass()
Log.v("MainActivity", "Fields: " + t.getFieldNames())
Log.v("MainActivity", "anotherVar: " + t.anotherVar)
t.setVal("anotherVar", 10)
Log.v("MainActivity", "anotherVar: " + t.anotherVar)

Results:

Fields: anotherVar, emptyClass, emptyTrait, contant, $kotlinClass
anotherVar: null
anotherVar: 10

it works )

Upvotes: 2

Related Questions