How can I instantiate an object using default constructor parameter values in Kotlin?

2.4k views Asked by At

I have data class with default values.

data class Project(
    val code: String,
    val name: String,
    val categories: List<String> = emptyList())

Java reflection fails to instantiate the class when some values are null. I'm getting exception

java.lang.IllegalArgumentException: Parameter specified as non-null is null: method Project.<init>, parameter categories

This is because java.lang.reflect.Constructor<T>.instantiateClass method expects arguments that are not null.

I have the type information, I have the constructor definition but I'm not sure how to call the constructor so that it uses the default values (The values are coming from the database and categories can be null). Is there any way to achieve this in Kotlin?

2

There are 2 answers

0
hotkey On

The Kotlin default parameters are not compatible with Java reflection, meaning there's no simple way to use them together, because the Kotlin default parameters actually work with a separate method under the hood that is also passed a bit mask to specify which arguments are default.

There are two ways to fix this.

0
Velmurugan V On

Using in Kotlin:

default values in constructors are taken only when the particular parameter of that constructor is not passed to it at all .That means it is done to achieve various combination of parameteraised constructor. for example,

data class Bird (val name: String = "peacock", val gender: String = "male")

takes default values when used as Bird(), Bird("dove") or Bird(gender ="female") .

so to solve your issue you have to add ? next to the categories parameter. like this,

data class Project(val code: String,
                   val name: String,
                   val categories: List<String>?)

and no need for emptyList() default. When you using emptyList as in your question you have to check for null and omit that parameter like this

val project = if(categories == null)
       {
          Project(code,name)
       }
       else
       {
          Project(code,name,categories)
       }

That is when using this data class in another kotlin class .

Using in JAVA:

But if you want to use this data class in any java class then as @Hotkey said it is not supported by default , as kotlin supports this default parameter by using some methods under the hood.

So to make it compatible with java class you have to add @JvmOverloads annotation but not as @Hotkey said it have to annotated like this

data class Project @JvmOverloads constructor(val code: String,
                                             val name: String,
                                             val categories: List<String>? = emptyList())