具有多态kotlinx序列化的自定义序列化程序
使用kotlinx.serialization多态性,我希望具有多态kotlinx序列化的自定义序列化程序,kotlin,serialization,polymorphism,kotlinx.serialization,Kotlin,Serialization,Polymorphism,Kotlinx.serialization,使用kotlinx.serialization多态性,我希望 {"type":"veh_t","owner":"Ivan","bodyType":"cistern","carryingCapacityInTons":5,"detachable":false} 但我明白了 {"type":"kotlin.collections.LinkedHashMap","owner":"Ivan","bodyType":"cistern","carryingCapacityInTons":5,"detach
{"type":"veh_t","owner":"Ivan","bodyType":"cistern","carryingCapacityInTons":5,"detachable":false}
但我明白了
{"type":"kotlin.collections.LinkedHashMap","owner":"Ivan","bodyType":"cistern","carryingCapacityInTons":5,"detachable":false}
我使用以下模型
interface Vehicle {
val owner: String
}
@Serializable
@SerialName("veh_p")
data class PassengerCar(
override val owner: String,
val numberOfSeats: Int
) : Vehicle
@Serializable
@SerialName("veh_t")
data class Truck(
override val owner: String,
val body: Body
) : Vehicle {
@Serializable
data class Body(
val bodyType: String,
val carryingCapacityInTons: Int,
val detachable: Boolean
//a lot of other fields
)
}
我应用以下Json
inline val VehicleJson: Json get() = Json(context = SerializersModule {
polymorphic(Vehicle::class) {
PassengerCar::class with PassengerCar.serializer()
Truck::class with TruckKSerializer
}
})
我使用serializer和serializer,因为服务器采用平面结构。同时,在应用程序中,我希望使用对象Truck.Body。对于扁平化,我根据这些类中的文档,在Serializator中使用JsonOutput和JsonInput重写fun序列化(编码器:编码器,obj:T)
和fun反序列化(解码器:解码器):T
object TruckKSerializer : KSerializer<Truck> {
override val descriptor: SerialDescriptor = SerialClassDescImpl("Truck")
override fun serialize(encoder: Encoder, obj: Truck) {
val output = encoder as? JsonOutput ?: throw SerializationException("This class can be saved only by Json")
output.encodeJson(json {
obj::owner.name to obj.owner
encoder.json.toJson(Truck.Body.serializer(), obj.body)
.jsonObject.content
.forEach { (name, value) ->
name to value
}
})
}
@ImplicitReflectionSerializer
override fun deserialize(decoder: Decoder): Truck {
val input = decoder as? JsonInput
?: throw SerializationException("This class can be loaded only by Json")
val tree = input.decodeJson() as? JsonObject
?: throw SerializationException("Expected JsonObject")
return Truck(
tree.getPrimitive("owner").content,
VehicleJson.fromJson<Truck.Body>(tree)
)
}
}
我最终得到了{“type”:“kotlin.collections.LinkedHashMap”,…}
,但我需要{“type”:“veh_t”,…}
我怎样才能得到正确的类型?我想对车辆使用多态性,并使用Truck.Body.serializer()对Body对象进行编码,以使其平坦化
通过这种序列化,PassengerCar类运行良好
VehicleJson.stringify(
PolymorphicSerializer(Vehicle::class),
PassengerCar(
owner = "Oleg",
numberOfSeats = 4
)
)
结果是正确的:
{"type":"veh_p","owner":"Oleg","numberOfSeats":4}
我认为问题在于自定义序列化程序TruckKSerializer
。
我注意到如果我在重写的fun序列化(encoder:encoder,obj:T)
next代码中使用
encoder
.beginStructure(descriptor)
.apply {
//...
}
.endStructure(descriptor)
我获得了正确的类型,但无法使用其序列化程序展平对象Truck.Body。打开和关闭组合的正确方法{}
这是密码吗
val composite = encoder.beginStructure(descriptor)
// use composite instead of encoder here
composite.endStructure(descriptor)
您应该能够使用.encodeSerializable(Body.serializer(),Body)
并始终传递描述符,否则它将返回到类似json字典的LinkedhashMap的内容在这种情况下,必须使用fun encodeStringElement(desc:SerialDescriptor,index:Int,value:String)
或fun encodeSerializableElement指定元素在描述符中的位置(desc:SerialDescriptor,index:Int,serializer:SerializationStrategy,value:T)
或其他什么。有可能避免这种情况吗?和。encodeSerializable(Body.serializer(),Body)
在beginStructure/endStructure中形成类似{commonFields,{bodyFields}}
的形式,但我需要一个平面结构`{commonFields,bodyFields}```。
val composite = encoder.beginStructure(descriptor)
// use composite instead of encoder here
composite.endStructure(descriptor)