I'm trying to serialize a Map<String,*> type.
Currently I'm decalring a SerializersModule, with any type that I'm storing in the map added here.
val module = SerializersModule {
polymorphic(Any::class) {
subclass(Int::class, PolymorphicPrimitiveSerializer(Int.serializer()))
subclass(String::class, PolymorphicPrimitiveSerializer(String.serializer()))
subclass(ComplexType::class)
}
}
I would like to enforce the compiler that only types that were defined in SerializersModule can be added to the map?
I'm open to hear other strategies to serialize star projected types Full code:
import kotlinx.serialization.*
import kotlinx.serialization.builtins.serializer
import kotlinx.serialization.descriptors.SerialDescriptor
import kotlinx.serialization.json.Json
import kotlinx.serialization.encoding.Decoder
import kotlinx.serialization.encoding.Encoder
import kotlinx.serialization.modules.SerializersModule
import kotlinx.serialization.descriptors.buildClassSerialDescriptor
import kotlinx.serialization.encoding.decodeStructure
import kotlinx.serialization.encoding.encodeStructure
import kotlinx.serialization.modules.*
import java.io.Serializable
@OptIn( ExperimentalSerializationApi::class )
class PolymorphicPrimitiveSerializer<T> (val typeSerializer: KSerializer<T>) : KSerializer<T>
{
override val descriptor: SerialDescriptor = buildClassSerialDescriptor( typeSerializer.descriptor.serialName )
{
element( "value", typeSerializer.descriptor )
}
override fun deserialize( decoder: Decoder ): T =
decoder.decodeStructure( descriptor )
{
decodeElementIndex( descriptor )
//TODO: what is this?
decodeSerializableElement( descriptor, 0,typeSerializer)
}
override fun serialize(encoder: Encoder, value: T) {
encoder.encodeStructure( descriptor )
{
encodeSerializableElement( descriptor, 0, typeSerializer, value )
}
}
}
data class MetaKey<T>(val name: String, val typ: Class<T>) : java.io.Serializable {
companion object {
inline fun <reified T: Serializable> named(name: String) =
MetaKey(name, T::class.javaObjectType)
}
}
fun emptyMetaMap() = mapOf<MetaKey<*>, Any>()
@kotlinx.serialization.Serializable
data class ComplexType(val i: Int)
fun main() {
val typesDictionary = mapOf(
"kotlin.Int" to Int::class.javaObjectType,
"ComplexType" to ComplexType::class.javaObjectType,
"kotlin.String" to String::class.javaObjectType )
val module = SerializersModule {
polymorphic(Any::class) {
subclass(Int::class, PolymorphicPrimitiveSerializer(Int.serializer()))
subclass(String::class, PolymorphicPrimitiveSerializer(String.serializer()))
subclass(ComplexType::class)
}
}
val format = Json { serializersModule = module }
val mm = emptyMetaMap()
.plus(MetaKey("complex type", ComplexType::class.javaObjectType) to ComplexType(1) )
.plus(MetaKey("Int one", Int::class.javaObjectType) to 1)
.plus(MetaKey("string value", String::class.javaObjectType) to "2B||!2B")
val jsoned = mm.keys.map {
listOf(
format.encodeToString(it.name),
format.encodeToString(PolymorphicSerializer(Any::class),mm[it] as Any),
)
}
var mmDecoded = emptyMetaMap()
jsoned.forEach {
val strKey = format.decodeFromString<String>(it[0])
val decodedVal = format.decodeFromString(PolymorphicSerializer(Any::class), it[1])
val strType = it[1].substringAfter("\"type\":\"").substringBefore("\"")
val metaKeyDeserialized = MetaKey(strKey, typesDictionary[strType] ?: throw IllegalArgumentException())
mmDecoded = mmDecoded.plus(metaKeyDeserialized to decodedVal)
}
assert(mmDecoded == mm)
}