如何使用Kotlin序列化为嵌套JSON组合多态序列化程序和转换序列化程序?
这是我想要使用的JSON的一个简化示例:如何使用Kotlin序列化为嵌套JSON组合多态序列化程序和转换序列化程序?,kotlin,Kotlin,这是我想要使用的JSON的一个简化示例: { “无用信息”:“无用信息”, “数据”:{ “无用信息2”:“无用信息2”, “儿童”:[ { “种类”:“汽车”, “数据”:{ “id”:1, “变速器”:“手动” } }, { “种类”:“船”, “数据”:{ “id”:2, “isDocked”:真 } } ] } } 子对象是车辆对象的数组车辆可以是船或汽车 我的问题 我想要的信息嵌套得很深(真正的JSON嵌套得很深)。一个hack解决方案是通过编写几十个相互引用的嵌套数据类来精确地建模
{
“无用信息”:“无用信息”,
“数据”:{
“无用信息2”:“无用信息2”,
“儿童”:[
{
“种类”:“汽车”,
“数据”:{
“id”:1,
“变速器”:“手动”
}
},
{
“种类”:“船”,
“数据”:{
“id”:2,
“isDocked”:真
}
}
]
}
}
子对象
是车辆
对象的数组<代码>车辆可以是船
或汽车
我的问题
我想要的信息嵌套得很深(真正的JSON嵌套得很深)。一个hack解决方案是通过编写几十个相互引用的嵌套数据类来精确地建模JSON。我不想这样做
我的问题是,虽然我知道如何使用JsonTransformingSerializer
来展开单个类型的数组,以及如何使用jsonContentPolymorphicsSerializer
来处理各种类型的对象,但在这种情况下,我相信我需要两者,但我无法让它工作
我所做的
假设单一类型
我试着理解如果它是一种单一的类型,它将如何工作
如果我想要的对象都是同一类型的,那么实现一个JsonTransformingSerializer
直接切入我想要的数据就很简单了。在本例中,我将假设我只关心ID,因此我可以创建一个通用的车辆
模型
@Serializable
数据类车辆响应(
@可序列化(with=VehiclerResponseSerializer::class)
@序列名(“数据”)
val车辆:列表
)
@可序列化
数据类车辆(val id:Int)
对象VehiclerResponseSerializer:JsonTransformingSerializer(ListSerializer(Vehicle.serializer())){
重写反序列化(元素:JsonElement):JsonElement{
val车辆=mutableListOf()
//等于:[{“种类”:“汽车”,“数据”:{“id”:1,“变速器”:“手动”},{“种类”:“船”,“数据”:{“id”:2,“isDocked”:true}]
val vehicleArray=element.jsonObject[“children”]!!.jsonArray
vehicleArray.forEach{vehicle->
//等于:{“id”:1,“变速器”:“手动”}
val vehicleData=vehicle.jsonObject[“数据”]!!
车辆.添加(车辆数据)
}
返回JsonArray(vehicles.toList())
}
}
代码工作得很好。从main调用它,打印结果会给我:
VehicleResponse(vehicles=[Vehicle(id=1), Vehicle(id=2)])
但它们实际上是多态的!
假设一种类型不起作用。我需要使用Car
和Boat
,并调用它们各自的函数和属性
我试图对结构进行如下建模:
@Serializable
数据类车辆响应(
@可序列化(with=VehiclerResponseSerializer::class)
@序列名(“数据”)
val车辆:列表
)
@可序列化
抽象类车辆{
抽象值id:Int
}
@可序列化
数据级汽车(
覆盖值id:Int,
val传输:字符串,
):车辆()
@可序列化
数据级船(
覆盖值id:Int,
val isDocked:布尔值,
):车辆()
我想要什么
- 我希望从服务器接收JSON,并立即能够将其反序列化为
对象列表,就像Vehicle
所拥有的那样vehiclerresponse
- 我想浏览一个深度嵌套的JSON,并打开一个包含各种
对象的数组。为此,我假设需要使用Vehicle
JsonTransformingSerializer
- 我想使用多态反序列化将
中的每一个转换为相应的子类型Vehicle
对象VehiclePolymorphicSerializer:JsonContentPolymorphicSerializer(VehiclerResponse::class){
重写反序列化器(元素:JsonElement):反序列化策略{
println(“\n选择反序列化程序()\n”+
“基本元素:\n”+
“$element\n”)
//这个返回是一个临时的hack,我只想通过将其打印到控制台来查看基本元素
return vehiclerResponse.serializer()
}
}
它打印:
selectDeserializer()
base element:
{"useless_info":"useless info","data":{"useless_info2":"useless info 2","children":[{"kind":"Car","data":{"id":1,"transmission":"manual"}},{"kind":"Boat","data":{"id":2,"isDocked":true}}]}}
这就是最初的全部JSON!如果Car
和Boat
都在那里,我应该如何决定使用哪种反序列化策略?JsonTransformingSerializer
在jsonContentPolymorphicsSerializer
之后调用
我真的不知道我该怎么做。即使是一个小小的提示也非常感谢。
kotlinx.serialization
在这种情况下可以处理多态反序列化,而无需定制jsonContentPolymorphicsSerializer
。您只需要在从JsonTransformingSerializer
返回的JSON中保留:
object VehicleResponseSerializer : JsonTransformingSerializer<List<Vehicle>>(ListSerializer(Vehicle.serializer())) {
override fun transformDeserialize(element: JsonElement): JsonElement {
// equals: [{"kind":"Car","data":{"id":1,"totalWheels":"4"}},{"kind":"Boat","data":{"id":2,"isDocked":true}}]
val vehicleArray = element.jsonObject["children"]!!.jsonArray
// equals: [{"id":1,"totalWheels":"4"}, {"id":2,"isDocked":true}] // Note that class discriminator is absent here!
return JsonArray(vehicleArray.map { it.jsonObject["data"]!! })
}
}
对象VehiclerResponseSerializer:JsonTransformingSerializer(ListSerializer(Vehicle.serializer())){
重写反序列化(元素:JsonElement):JsonElement{
//等于:[{“种类”:“汽车”,“数据”:{“id”:1,“totalWheels”:“4”},{“种类”:“船”,“数据”:{“id”:2,“isDocked”:true}]
val vehicleArray=element.jsonObject[“children”]!!.jsonArray
//等于:[{“类型”:“汽车”,“id”:1,“totalWheels”:“4”},{“类型”:“船”,“id”:2,“isDocked”:true}]
返回JsonArray(vehiclarray.map{
val data=it.jsonObject[“数据”]!!.jsonObject
val type=it.jsonObject[“种类”]!!
JsonObject(
data.toMutableMap().apply{this[“type”]=type}
/*
val kotlinx = Json {
ignoreUnknownKeys = true
serializersModule = module
}
object VehicleResponseSerializer : JsonTransformingSerializer<List<Vehicle>>(ListSerializer(Vehicle.serializer())) {
override fun transformDeserialize(element: JsonElement): JsonElement {
// equals: [{"kind":"Car","data":{"id":1,"totalWheels":"4"}},{"kind":"Boat","data":{"id":2,"isDocked":true}}]
val vehicleArray = element.jsonObject["children"]!!.jsonArray
// equals: [{"id":1,"totalWheels":"4"}, {"id":2,"isDocked":true}] // Note that class discriminator is absent here!
return JsonArray(vehicleArray.map { it.jsonObject["data"]!! })
}
}
object VehiclePolymorphicSerializer : JsonContentPolymorphicSerializer<Vehicle>(Vehicle::class) {
override fun selectDeserializer(element: JsonElement): DeserializationStrategy<out Vehicle> = when {
"isDocked" in element.jsonObject -> Boat.serializer()
else -> Car.serializer()
}
}
val module = SerializersModule {
polymorphicDefault(Vehicle::class) { VehiclePolymorphicSerializer }
}
val kotlinx = Json {
ignoreUnknownKeys = true
serializersModule = module
}