按使用 kotlinx.serialization 生成的键排序的地图

Map sorted by keys generated with kotlinx.serialization

我需要用地图序列化 class,以便地图中的键在 json 中排序。所以如果有 class

@Serializable
class Example(val map: Map<String, Int>)

并且序列化为

val example = Example(mapOf("b" to 2, "a" to 1, "c" to 3))
println(Json.encodeToString(example))

那么结果 json 应该是

{
    "map": {
        "a": 1,
        "b": 2,
        "c": 3
    }
}

我尝试使用 SortedMap 而不是 Map,但会引发异常:

kotlinx.serialization.SerializationException: Class 'TreeMap' is not registered for polymorphic serialization in the scope of 'SortedMap'

如何使用 kotlinx.serialization 获得排序的 json?

(kotlin 1.4.0, kotlinx.serialization 1.0.0-RC)

想通了:

import kotlinx.serialization.*
import kotlinx.serialization.json.*
import kotlinx.serialization.builtins.*
import kotlinx.serialization.descriptors.SerialDescriptor
import kotlinx.serialization.encoding.Decoder
import kotlinx.serialization.encoding.Encoder

object SortedMapSerializer: KSerializer<Map<String, Int>> {
    private val mapSerializer = MapSerializer(String.serializer(), Int.serializer())
    
    override val descriptor: SerialDescriptor = mapSerializer.descriptor

    override fun serialize(encoder: Encoder, value: Map<String, Int>) {
        mapSerializer.serialize(encoder, value.toSortedMap())
    }

    override fun deserialize(decoder: Decoder): Map<String, Int> {
        return mapSerializer.deserialize(decoder)
    }
}

@Serializable
class Example(
    @Serializable(with = SortedMapSerializer::class)
    val map: Map<String, Int>
)

fun main() {
    val example = Example(mapOf("b" to 2, "c" to 3, "a" to 1))
    println(Json.encodeToString(
        example
    ))
}

(如果能得到 Map<Serializable, Serializable>

的答案就好了