1

Hi everyone I have the following code that I use to serialize into json strings to store in shared preferences

interface Serializer {
  public fun <T> serialize(data: T, type: Class<T>): String
  public fun <T> deserialize(source: String, type: Class<T>): T?
}

I can later create implementations of this class and serialize my objects using Moshi like the following

class SerializerImpl(
private val moshi: Moshi = Moshi.Builder()
    .build(),
) : Serializer {

override fun <T> deserialize(source: String, type: Class<T>): T? = try {
    moshi.adapter(type).fromJson(source)
} catch (exception: Exception) {
    null
}

override fun <T> serialize(data: T, type: Class<T>): String = 
   moshi.adapter(type).toJson(data)
}

Can you advice how to migrate this implementation to use kotlinx serialization without having to change the signature of the Serializer interface it seems like I must change the type of my Serializer interface to use KSerializer in order for this to work but I would really like to avoid that.

1 Answer 1

1

Kotlinx.serialization provides an experimental support for acquiring serializers (KSerializer) dynamically for the provided Type or KType. We can use it to easily implement the Serializer:

class KotlinxSerializer : Serializer {
    override fun <T> serialize(data: T, type: Class<T>) = Json.encodeToString(type.serializer(), data)
    override fun <T> deserialize(source: String, type: Class<T>) = Json.decodeFromString(type.serializer(), source)
}

@OptIn(ExperimentalSerializationApi::class)
@Suppress("UNCHECKED_CAST")
private fun <T> Class<T>.serializer() = Json.serializersModule.serializer(this) as KSerializer<T>

Usage:

fun main() {
    val ser = KotlinxSerializer()
    val d1 = MyData("hello")
    val s = ser.serialize(d1, MyData::class.java)
    println(s) // {"foo":"hello"}
    val d2 = ser.deserialize(s, MyData::class.java)
    println(d2) // MyData(foo=hello)
}

@Serializable
data class MyData(val foo: String)

Please note we still have to mark all data classes with @Serializable. Kotlinx.serialization can't work without this as this is a compile-time serialization framework.

Sign up to request clarification or add additional context in comments.

3 Comments

Do you know how to do this with List and Map as well?
@BitwiseDEVS Pretty much the same, but please note we can't represent a list/map with its type params as a Class/KClass. We need Type/KType. If you have one of these, you can use almost the same code as above. If you only have Class, then it doesn't describe the type fully. If your case isn't entirely generic and it is always a list of some generic T, then you can use ListSerializer.
I have idea how to do it in Moshi however I can't see any approach with KotlinX Serialization yet, I already file an issue here: github.com/Kotlin/kotlinx.serialization/issues/2720

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.