我有一个针对网络流量进行序列化的类。
@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
字段。
这是最糟糕的22。该框架不会忽略该payload: Any
字段(产生编译错误),而且我什至无法编写自定义序列化程序,因为在客户序列化程序(用于描述符)中定义element
类型类型Any
会产生与“未注册序列化程序”相同的运行时错误。为Any
。”
我已经使用Java序列化通过网络发送它。接收者无法知道有效载荷的类型,但是Java将其反序列化就很好了,然后我使用when(dataType)作为查找来正确将Any对象转换为正确的类型。容易疯了。
这是因为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)
}
}
}
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句