gpt4 book ai didi

kotlin - 如何在 Kotlinx 序列化中序列化 "Any"类型?

转载 作者:行者123 更新时间:2023-12-04 12:09:41 52 4
gpt4 key购买 nike

我有一个为网络流量序列化的类。

@Serializable    
data class Packet(val dataType: String, val payload: Any)
我已经使用 Java 序列化通过网络发送它。接收者无法知道有效载荷的类型,但 Java 反序列化它就好了,然后我使用 when(dataType)作为正确转换 Any 的查找反对其正确的类型。轻松活泼。
但是 Kotlinx 序列化(使用 ProtoBuf)对此持保留态度 Any键入的原因对我来说并不明显。我无法为 Any 注册序列化程序.在文档中,他们推荐了一种多态方法,这可以正常工作,但您必须输入数据包:
data class Packet<out T : Any>(val dataType: String, val payload: T) : SomeBaseClass<T>
但这有点糟糕,因为它使用内联具体化类型压低了很多代码路径,而且这并不能解决接收端不知道尝试反序列化有效负载的类型而无需查看 dataType场第一。
这是最糟糕的 catch-22。框架不会忽略 payload: Any字段(给出编译错误),我什至无法编写自定义序列化程序,因为定义了 element类型 Any在客户序列化程序中(用于描述符)给出了“没有为 Any 注册的序列化程序”的相同运行时错误。

最佳答案

I've used Java serialization to send it over the wire. The receiver can't know the type of the payload but Java deserializes it just fine, and then I use when(dataType) as a lookup to correctly cast the Any object to its correct type. Easy breazy.


这是因为 java 序列化相当原始 - 只有一种方法可以序列化(并因此反序列化)一个对象。在 kotlinx.serialization 中,每个类都可以有自己的序列化策略(甚至几个)。这种灵活性是有代价的。 Any系列化可以处理(对于其子类的声明列表),但是基于 dataType 的反序列化策略的动态确定部分反序列化对象的字段在一般情况下是不可能的,因为不能保证 dataType字段将首先反序列化。一些序列化格式(如 JSON 或 Protobuf)具有无序模式。可能会发生 payload之前即将被反序列化 dataType , 和 Decoder界面不允许返回/进行多次传递。
如果您确定序列化格式/消息中的属性顺序(或者只是觉得很幸运),您可以使用以下自定义序列化程序:
import kotlinx.serialization.*
import kotlinx.serialization.descriptors.*
import kotlinx.serialization.encoding.*

@Serializable(with = PacketSerializer::class)
data class Packet(val dataType: String, val payload: Any)

object PacketSerializer : KSerializer<Packet> {
override val descriptor: SerialDescriptor = buildClassSerialDescriptor("Packet") {
element("dataType", serialDescriptor<String>())
element("payload", buildClassSerialDescriptor("Any"))
}

@Suppress("UNCHECKED_CAST")
private val dataTypeSerializers: Map<String, KSerializer<Any>> =
mapOf(
"String" to serializer<String>(),
"Int" to serializer<Int>(),
//list them all
).mapValues { (_, v) -> v as KSerializer<Any> }

private fun getPayloadSerializer(dataType: String): KSerializer<Any> = dataTypeSerializers[dataType]
?: throw SerializationException("Serializer for class $dataType is not registered in PacketSerializer")

override fun serialize(encoder: Encoder, value: Packet) {
encoder.encodeStructure(descriptor) {
encodeStringElement(descriptor, 0, value.dataType)
encodeSerializableElement(descriptor, 1, getPayloadSerializer(value.dataType), value.payload)
}
}

@ExperimentalSerializationApi
override fun deserialize(decoder: Decoder): Packet = decoder.decodeStructure(descriptor) {
if (decodeSequentially()) {
val dataType = decodeStringElement(descriptor, 0)
val payload = decodeSerializableElement(descriptor, 1, getPayloadSerializer(dataType))
Packet(dataType, payload)
} else {
require(decodeElementIndex(descriptor) == 0) { "dataType field should precede payload field" }
val dataType = decodeStringElement(descriptor, 0)
val payload = when (val index = decodeElementIndex(descriptor)) {
1 -> decodeSerializableElement(descriptor, 1, getPayloadSerializer(dataType))
CompositeDecoder.DECODE_DONE -> throw SerializationException("payload field is missing")
else -> error("Unexpected index: $index")
}
Packet(dataType, payload)
}
}
}

关于kotlin - 如何在 Kotlinx 序列化中序列化 "Any"类型?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/66148137/

52 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com