The way that Kotlin Serialisation works is that the serialisation code for each serialisable thing is generated in the companion object of the class, by processing the @Serializable
annotation at compile time.
So something like
@Serializable
class Foo(val name: String)
becomes
@Serializable
class Foo(val name: String) {
companion object {
fun serializer(): KSerializer<Foo> {
// implementation details...
// returns a serializer for Foos in some way
}
}
}
Interfaces can't require a type to have a companion object. Interfaces can only require things related to instances of a type, after all. So there is no interface for this.
As is said in this Kotlin forums comment, one way you could guarantee a successful serialisation is to require the caller to pass in the generated serializer()
:
class MyWrapperClass<T>(
val someData: T,
val strategy: SerializationStrategy<T>
) {
fun stringifyMe(): String {
return Json.encodeToString(strategy, someData)
}
}
If the caller has a serialisable type, then they could do:
MyWrapperClass(someData, SomeSerializableType.serializer())
Even if a type is not marked with @Serializable
, but the caller has got a SerializationStrategy
for it using some other means, it is also possible to serialise the instance, and so is by definition, "serialisable".
I don't recommend this, but it is also possible to declare these two interfaces:
interface SerializationStrategyProvider<T> {
fun serializer(): SerializationStrategy<T>
}
interface MySerializable<T: MySerializable<T>> {
val serializationStrategyProvider: SerializationStrategyProvider<T>
}
Then your wrapper class can just have one parameter:
class MyWrapperClass<T: MySerializable>(val someData: T) {
fun stringifyMe(): String {
return Json.encodeToString(someData.serializationStrategyProvider.serializer(), someData)
}
}
But the downside is of course that the callers need to implement this interface before they can use your class, and you cannot enforce how they implement this interface. The expected way is:
@Serializable
data class Foo(val bar: String): MySerializable<Foo> {
companion object: SerializationStrategyProvider<Foo>
override val serializationStrategyProvider
get() = Foo
}