Igor Kolomiets
05/25/2022, 2:53 PM@Serializable
data class Category(val id: String, val children: Set<Category> = emptySet())
For the sake of having “stable” diff of the updated JSON file, I’d like to enforce order of the children
Set’s elements based on lexicographic order of the element’s id
field.
The solution I was able to come up with is to use custom serializer based on `JsonTransformingSerializer`:
object CategorySetSerializer : JsonTransformingSerializer<Set<Category>>(SetSerializer(Category.serializer())) {
override fun transformSerialize(element: JsonElement) = super.transformSerialize(
if (element is JsonArray)
JsonArray(element.sortedBy { it.jsonObject["id"]?.jsonPrimitive?.content })
else
element
)
}
@Serializable
data class Category(
val id: String,
@Serializable(with = CategorySetSerializer::class)
val children: Set<Category> = emptySet()
)
Unfortunately, this solution seems too low level, brittle and JSON specific.
What can be other approaches to enforce particular ordering of serialized Set’s elements?
Ideally, I’d like to pass in the @Serializable
my custom comparator when specific Set’s elements ordering is required.ephemient
05/25/2022, 3:17 PM@Serializable
data class Category(val id: String, @Serializable(SortedCategorySetSerializer::class) val children: Set<Category> = emptySet())
object SortedCategorySetSerializer : KSerializer<Set<Category>> {
private val listSerializer = ListSerializer(Category.serializer())
override val descriptor: SerialDescriptor = listSerializer.descriptor
override fun serialize(encoder: Encoder, value: Set<Category>) {
encoder.encodeSerializableValue(listSerializer, value.sortedBy { it.id })
}
override fun deserialize(decoder: Decoder): Set<Category> {
return decoder.decodeSerializableValue(listSerializer).toSortedSet(compareBy { it.id })
}
}