Actually, the main problem is still that there are no reified typeargs for classes in Kotlin. But here is why this bothers me in this specific case:
Suppose you have a wrapper class Wrapper
that takes in a string content
and a class* type
and can output an object of class type
retrieved by parsing content
as JSON by demand by calling the function getObj()
:
class Wrapper<T>(private val content: String, /*private val type: KClass<*>*/) {
fun getObj(): T {
// ?
}
}
And I want to use kotlinx.serialization. Now, you might have noticed how I put an asterisk after "class" before. Here's the reason: Yes, Wrapper
has to take the target class in some way, but how? Should it be just the typearg (won't work because type erausre) or a KClass
reference (won't work because I need a reified typearg)?
The thing is that as far as I know, the only way to decode a generic JSON to a serializable target class is to use Json.decodeFromString<T>(content)
, where T
is the target type and content
is the JSON string. Now, T
is defined to be reified (so that the type can be processed at runtime) and can only be filled with another reified typearg or an actual class reference. I can't use another reified typearg because I am in the context of a class and a class cannot have reified typeargs. I can also not use an actual class reference because the user of the class should be able to construct it with different targets, e.g. they decide what the target is, not me.
So, how do I do this with kotlinx.serialization? Is it even possible?
Ok so no one answered the question yet, but I also posted this question in the r/Kotlin subreddit. Here it is.
I actually got an answer there (credits to u/JakeWharton), and since you might get across this StackOverflow question because you googled the same question, you might be happy to find an answer here. So here's my try to paraphrase the answer:
So, basically, kotlinx-serialization does indeed not work with
KClass
es. But when you think about it, you only need theKClass
to determine how to serialize it. And since that is determined at compile-time when you work with KXS, you actually just need to pass the serializer (the actual strategy defining how to serialize / deserialize your class). You can obtain a serializer for every class annotated with@Serializable
by invoking.serializer()
on it; the result will be of the typeKSerializer<T>
. So, instead of havingand constructing it via
You can do it like this:
and then construct it like this:
(supposing
Foo
is annotated with@Serializable
)you can then serialize and deserialize by using the
KSerializer
instead of a typearg, like this:And that's it! Just swap out your regular
(K)Class
approach byKSerializer
and it'll work with KXS.