具有多态kotlinx序列化的自定义序列化程序

具有多态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

使用kotlinx.serialization多态性,我希望

{"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)