How to get default value of field defined in data class using reflection?

159 views Asked by At

I have data class with the format-

data class ABC(
    var first: String,
    var second: String,
    var third: String = "value"
) 

I am using the below method to create an instance

T::class.java.getDeclaredConstructor().newInstance()

Now, this method calls the empty constructor and creates an instance with values of first as null, second as null and third as null , even though these are non-nullable field.

What I want is to create a instance with values of first as null, second as null but third as value.

Is there any way I can get the default value after creating the instance and than I will set the values manually?

I tried to directly get the memeber properties of the class but to call the property and get the value I have to pass the instance. If I pass the instance created with the above method I will get the value of third as null.

2

There are 2 answers

2
Klitos Kyriacou On

If you want an instance of ABC with properties null, null and default "value", you first need to declare the constructor to allow nullable properties:

data class ABC(
    var first: String?,
    var second: String?,
    var third: String = "value"
)

I would strongly recommend that you consider making the data class immutable, by using val instead of var, unless you really need it to be mutable.

You're trying to use T::class.java, which is not going to work because Java does not have a concept of default parameters. You need to use T::class instead, which returns a KClass, part of Kotlin's reflection system which does understand default parameters.

To use default parameters, create a map of required parameters to values, leaving out those that you want to leave as default:

import kotlin.reflect.full.primaryConstructor

fun main() {
    val constructor = ABC::class.primaryConstructor ?: error("missing constructor")
    val params = constructor.parameters
    val instance = constructor.callBy(mapOf(params[0] to "p1", params[1] to "p2"))
    println(instance)  // ABC(first = p1, second = p2, third = value)
}
1
Mohsen On

you can do it like this using callBy, but I don't know any way that you can pass null to non-null properties, here is the code:

fun main() {
    val cons = ABC::class.constructors.first()
    val params = cons.parameters
    val x = ABC::class.constructors.first().callBy(
        mapOf(
            params[0] to "",
            params[1] to ""
        )
    )
    println(x)
}