New to kotlinx-serialization. I have a bunch of ty...
# serialization
c
New to kotlinx-serialization. I have a bunch of types that i currently use a Map for
Copy code
{
  "items": [
    { "x": { // bunch of properties} },
    { "y": { // bunch of properties, identical to above} },
    { "z": { // ^^^} },
    { "x (again)": { // ^^^} },
  ]
}
A Map is kinda error prone. is this something I can use a custom type for like
data class Element(val name: String, val otherProperty1: Int, val otherProperty2: Int)
and have it convert to the above?
😱 1
a
Yeah, using a custom type would be better than a map If I assume that x/y/z are actually all named x, then this would work, right?
Copy code
@Serializable
data class ItemsHolder(
  val items: List<Item>
)

@Serializable
data class Item(
  val x: Element
)

@Serializable
data class Element(val name: String, val otherProperty1: Int, val otherProperty2: Int)
the quick and easy way to re-use the
Item
class would be to use
@JsonNames
, so the property might be called
x
but you can also add
y
and
z
as alternate names • https://kotlinlang.org/api/kotlinx.serialization/kotlinx-serialization-json/kotlinx.serialization.json/-json-names/ • https://github.com/Kotlin/kotlinx.serialization/blob/v1.5.1/docs/json.md#alternative-json-names
c
thanks that should give me a good starting point
ill circle back when im back at my desk
e
if I understand your format correctly, then https://github.com/Kotlin/kotlinx.serialization/blob/master/docs/serializers.md#composite-serializer-via-surrogate is useful, once again
Copy code
@Serializable(with = ItemSerializer::class)
data class Item(val name: String, val prop1: String, val prop2: String)

@Serializable
private data class ItemSurrogate(val prop1: String, val prop2: String)

object ItemSerializer : KSerializer<Item> {
    private val serializer = MapSerializer(String.serializer(), ItemSurrogate.serializer())
    override val descriptor = serializer.descriptor

    override fun serialize(encoder: Encoder, value: Item) {
        encoder.encodeSerializableValue(
            serializer,
            mapOf(value.name to ItemSurrogate(prop1 = value.prop1, prop2 = value.prop2))
        )
    }

    override fun deserialize(decoder: Decoder): Item {
        val (name, value) = decoder.decodeSerializableValue(serializer).entries.single()
        return Item(name = name, prop1 = value.prop1, prop2 = value.prop2)
    }
}
or https://github.com/Kotlin/kotlinx.serialization/blob/master/docs/json.md#json-transformations but I think it's more error-prone
Copy code
@Serializable(with = ItemSerializer::class)
data class Item(val name: String, val prop1: String, val prop2: String)

@Serializer(forClass = Item::class)
private object ItemDefaultSerializer

object ItemSerializer : JsonTransformingSerializer<Item>(ItemDefaultSerializer) {
    override fun transformSerialize(element: JsonElement): JsonElement = buildJsonObject {
        val map = element.jsonObject.toMutableMap()
        putJsonObject(map.remove("name")!!.jsonPrimitive.content) {
            for ((key, value) in map) {
                put(key, value)
            }
        }
    }

    override fun transformDeserialize(element: JsonElement): JsonElement = buildJsonObject {
        val (name, nested) = element.jsonObject.entries.single()
        put("name", name)
        for ((key, value) in nested.jsonObject) {
            put(key, value)
        }
    }
}