具有多态Kotlinx序列化的自定义序列化器

时间:2019-10-18 14:19:07

标签: 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,"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
        }
    })

我使用串行器TruckKSerializer,因为服务器采用扁平结构。同时,在应用程序中,我想使用对象Truck.Body。为了展平,我根据这些类中的文档使用JsonOutput和JsonInput在Serializator中重写fun serialize(encoder: Encoder, obj : T)fun deserialize(decoder: Decoder): 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)
        )
    }
}

最后,我使用stringify(serializer: SerializationStrategy<T>, obj: T)

VehicleJson.stringify(
    PolymorphicSerializer(Vehicle::class),
    Truck(
        owner = "Ivan",
        body = Truck.Body(
            bodyType = "cistern",
            carryingCapacityInTons = 5,
            detachable = false
        )
    )
)

我最终得到{"type":"kotlin.collections.LinkedHashMap", ...},但我需要{"type":"veh_t", ...} 如何获得正确的类型?我想对Vehicle使用多态性,并使用Truck.Body.serializer()对Body对象进行编码以使其变平。

通过此序列化,PassengerCar类运行良好。

VehicleJson.stringify(
    PolymorphicSerializer(Vehicle::class),
    PassengerCar(
        owner = "Oleg",
        numberOfSeats = 4
    )
)

结果正确:

{"type":"veh_p","owner":"Oleg","numberOfSeats":4}

我认为问题在于自定义序列化程序TruckKSerializer。 而且我注意到是否在覆盖的fun serialize(encoder: Encoder, obj : T)下一个代码

中使用了
encoder
            .beginStructure(descriptor)
            .apply { 
                //...
            }
            .endStructure(descriptor)

我得到正确的类型,但是无法使用其序列化器展平对象Truck.Body。

1 个答案:

答案 0 :(得分:0)

打开和关闭组合<v:content.render column="0" limit="10" pageUid="35" as="contentElements"></v:content.render> 的正确方法 这是代码

{}

,您应该可以使用val composite = encoder.beginStructure(descriptor) // use composite instead of encoder here composite.endStructure(descriptor) 来序列化Body

并始终传递描述符,否则它将退回到JSON字典的LinkedhashMap之类的东西