如何使用kotlin kotlinx序列化来序列化自相关结构?

如何使用kotlin kotlinx序列化来序列化自相关结构?,kotlin,serialization,Kotlin,Serialization,我有一些关于db对象的元数据,我想通过网络发送,包括某行的id。由于kotlin提供了现成的Json序列化,我非常愿意使用它。 现在的问题是,ID的类型可以是任何类型,实际上目前只有Int、Long或UUID。现在我有了描述密钥类型的元数据,所以在这两方面我都可以提供一个(反)序列化器。 因此,我: @file:ContextualSerialization(MetaData::class, Any::class) package com.example sealed class MetaPr

我有一些关于db对象的元数据,我想通过网络发送,包括某行的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)

@file:ContextualSerialization(MetaData::class,Any::class)
包com.example
密封类元属性(val名称:字符串,val类型:KClass){
抽象乐趣序列化程序():KSerializer
}
类IntProperty(名称:String):元属性(名称,Int::class){
重写有趣的序列化程序():KSerializer=IntSerializer作为KSerializer
}
类元数据(val类型:String,val idType:MetaProperty)
@可序列化
数据类关系(
val from:元数据,
瓦尔·弗罗密德:任何,
val to:元数据,
瓦尔·托伊德:有吗
现在我只想序列化关系,实际上在我的例子中,只有关系的to端(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!!)
    }
}

@Serializer(forClass=DBRelation::class)
对象关系序列化程序:KSerializer{
lateinit var meta:(字符串)->元数据
重写val描述符:SerialDescriptor=对象:SerialClassDescImpl(“关系”){
初始化{
增补(“来自”)
增编(“至”)
附加元素(“fromId”)
附录(“toId”)
}
}
@隐式反射序列化程序
重写有趣的序列化(编码器:编码器,obj:DBRelation){
val comp=编码器.beginStructure(描述符)
comp.encodeStringElement(描述符,0,对象自类型)
comp.encodeSerializableElement(描述符,2,对象自.idType.type.serializer()作为KSerializer,对象自ID)
}
重写有趣的反序列化(解码器:解码器):DBRelation=run{
变量来源:字符串?=null
变量到:字符串?=null
var fromId:Any?=null
var toId:有吗?=null
val dec=解码器.beginStructure(描述符)
循环@while(true){
当(val idx=dec.decodeElementIndex(描述符)){
compositedCoder.READ\u DONE->break@loop
0->from=dec.decodeStringElement(描述符,idx)
1->to=dec.decodeStringElement(描述符,idx)
2->fromId=dec.decodeSerializableElement(描述符、idx、元(从?:抛出IllegalStateException()).idType.serializer())
}
}
数据库关系(meta(from!!)、fromId!!、meta(to!!)、toId!!)
}
}
现在,这个实现可能工作,也可能不工作,这取决于字段反序列化的顺序

所以我有两个问题:

有人知道解决我问题的另一种方法吗?一个不需要我为每个可能的键类型组合编写特殊关系类的类


B.更好的是,有没有办法告诉序列化程序在反序列化
from
之前保留ID值?或者给我一些ID的序列化版本,我可以稍后(一旦我从值`)反序列化?

你能将两个ID解码为字符串,然后根据元数据将它们解析为Int、Long或UUID吗?@SpaceBison好吧,这是可能的,但我感觉这会使整个系统变得脆弱。我可以提供类似于
asString
/
fromString
方法到PropertyMeta的东西,但这意味着如果任何人想要序列化他的类或使用任意复杂键,他也必须提供这些方法,而不是用
@Serilizable
标记这些类。