Secondary constructor initiation logic on data class

I have a generic data class like:

data class ConfigurationDTO<T : Any>(
    val id: Long,
    val key: String,
    var value: T
)

And I would like to have a constructor where I could pass the value as String and a KClass to deserialize it. The problem is Kotlin oblies me to call this() on the secondary constructor and I have no value for value yet:

   constructor(id: Long, key: String, valueStr: String, klazz: KClass<T>)
       : this(id, key, ??????)

What I would like to do is the equivalent like:

   // Doesn't work
   constructor(id: Long, key: String, valueStr: String, klazz: KClass<T>) {
       val value = // Deserialize, initialize logic with valueSTR and klazz...
       this(id, key, value)
   }

So, processing the parameters before calling the constructor.
What is the best way to do it?

Thanks

Just use a factory method. Usually those are on the companion object.

In my opinion, secondary constructors should not be used at all. As @al3c said, use factory methods.

1 Like

However though, if you do want to use a secondary constructor, you can use a top-level method like so:

import kotlin.reflect.*
data class ConfigurationDTO<T : Any>(
    val id: Long,
    val key: String,
    var value: T
) {
   constructor(id: Long, key: String, valueStr: String, klazz: KClass<T>): this(id, key, deserializeValueFromKClass(valueStr, klazz))
}

fun <T : Any> deserializeValueFromKClass(valueStr: String, klazz: KClass<T>): T {
   val value: T = TODO() // Deserialize, initialize logic with valueSTR and klazz...
   return value
}

(In general, even if X isn’t a recommended practice in one situation, there are reasons why sometimes you’d want to use X (e.g. for secondary constructors, JVM interop, so I think it’s apt to want an answer)