如何使用Kotlin Kotlinx序列化序列化自相关结构?

时间:2019-11-06 07:08:37

标签: kotlin serialization

我有一些有关数据库对象的元数据,我想通过网络发送,包括某些行的ID。由于kotlin开箱即用地提供了Json序列化,我非常愿意使用它。 现在的问题是ID的类型可以是任何类型,实际上目前仅是Int,Long或UUID。现在,我有了描述密钥类型的元数据,因此在两面都可以提供一个(反序列化器)。 所以我有:

@file:ContextualSerialization(MetaData::class, Any::class)
package com.example

sealed class MetaProperty(val name:String, val type: KClass<*>) {
    abstract fun serializer() : KSerializer<Any>
}
class IntProperty(name:String) : MetaProperty(name, Int::class) {
    override fun serializer(): KSerializer<Any> = IntSerializer as KSerializer<Any>
}

class MetaData(val type:String, val idType:MetaProperty)

@Serializable
data class DBRelation(
        val from:MetaData,
        val fromId: Any,
        val to:MetaData,
        val toId:Any)

现在,我只想序列化Relation,实际上,在我的情况下,仅关系的另一端(不需要from),我只是包含了它以使序列化成为可能。 我写了一个自定义序列化程序的幼稚实现:

@Serializer(forClass = DBRelation::class)
object RelationToSerializer : KSerializer<DBRelation> {
    lateinit var meta : (String) -> MetaData
    override val descriptor: SerialDescriptor = object : SerialClassDescImpl("relation") {
        init {
            addElement("from")            
            addElement("to")
            addElement("fromId")
            addElement("toId")
        }
    }

    @ImplicitReflectionSerializer
    override fun serialize(encoder: Encoder, obj: DBRelation) {
        val comp = encoder.beginStructure(descriptor)
        comp.encodeStringElement(descriptor, 0, obj.from.type)
        comp.encodeSerializableElement(descriptor, 2, obj.from.idType.type.serializer() as KSerializer<Any>, obj.fromId)

    }

    override fun deserialize(decoder: Decoder): DBRelation = run {
        var from : String? = null
        var to : String? = null
        var fromId : Any? = null
        var toId : Any? = null
        val dec = decoder.beginStructure(descriptor)
        loop@ while (true) {
            when(val idx = dec.decodeElementIndex(descriptor)) {
                CompositeDecoder.READ_DONE -> break@loop
                0 ->  from = dec.decodeStringElement(descriptor, idx)
                1 -> to = dec.decodeStringElement(descriptor, idx)
                2 -> fromId = dec.decodeSerializableElement(descriptor, idx, meta(from?:throw IllegalStateException()).idType.serializer())
            }
        }
        DBRelation(meta(from!!), fromId!!, meta(to!!), toId!!)
    }
}

现在,根据字段反序列化的顺序,此实现可能会起作用,也可能不会起作用。

所以我有两个问题:

A。有人知道我的问题的另一种解决方案吗?哪个不需要我为每种可能的Key类型组合编写特殊的Relation类?

B。更好的是,有没有办法告诉串行器保留ID值,直到from被反序列化为止?还是给我一些ID的序列化版本,以便以后可以对它进行序列化(一旦我有了from值)就可以反序列化?

0 个答案:

没有答案