Kotlin:将嵌套的 JSON 对象转换为文字字符串
Kotlin: convert nested JSON object to literal string
我有一个数据 class,它有一个 属性,其类型是另一个数据 class,像这样:
@Serializable
data class Vehicle (
val color: String,
val miles: Int,
val year: Int,
val garage: Garage
)
@Serializable
data class Garage (
val latitude: Float,
val longitude: Float,
val name: String
)
序列化后,它会产生如下输出:
{
"color" : "black" ,
"miles" : 35000 ,
"year" : 2017 ,
"garage" : { "latitude" : 43.478342 , "longitude" : -91.337000 , "name" : "Paul's Garage" }
}
但是我希望 garage
是其 JSON 表示的文字字符串,而不是实际的 JSON 对象。换句话说,期望的输出是:
{
"color" : "black" ,
"miles" : 35000 ,
"year" : 2017 ,
"garage" : "{ \"latitude\" : 43.478342 , \"longitude\" : -91.337000 , \"name\" : \"Paul's Garage\" }"
}
如何在 Kotlin 中完成此操作?仅需 kotlinx.serialization
即可完成还是绝对需要 Jackson/Gson?
请注意,此输出用于特定用途。我无法覆盖基本序列化程序,因为我仍然需要从正常的 JSON(第一个示例)中 serialize/deserialize。换句话说,最好的方案是将第一个 JSON 样本转换为第二个样本,而不一定要让数据 class 直接生成第二个样本。
谢谢!
为 Vehicle
创建自定义 SerializationStrategy
,如下所示:
val vehicleStrategy = object : SerializationStrategy<Vehicle> {
override val descriptor: SerialDescriptor
get() = buildClassSerialDescriptor("Vehicle") {
element<String>("color")
element<Int>("miles")
element<Int>("year")
element<String>("garage")
}
override fun serialize(encoder: Encoder, value: Vehicle) {
encoder.encodeStructure(descriptor) {
encodeStringElement(descriptor, 0, value.color)
encodeIntElement(descriptor, 1, value.miles)
encodeIntElement(descriptor, 2, value.year)
encodeStringElement(descriptor, 3, Json.encodeToString(value.garage))
}
}
}
然后传给Json.encodeToString()
:
val string = Json.encodeToString(vehicleStrategy, vehicle)
结果:
{"color":"black","miles":35000,"year":2017,"garage":"{\"latitude\":43.47834,\"longitude\":-91.337,\"name\":\"Paul's Garage\"}"}
更多信息here
这是一个解决方案,其中包含用于 Garage
的自定义序列化程序和用于 Vehicle
的附加 class。
Garage
到 String
序列化程序:
object GarageToStringSerializer : KSerializer<Garage> {
override val descriptor = PrimitiveSerialDescriptor("GarageToString", PrimitiveKind.STRING)
override fun serialize(encoder: Encoder, value: Garage) = encoder.encodeString(Json.encodeToString(value))
override fun deserialize(decoder: Decoder): Garage = Json.decodeFromString(decoder.decodeString())
}
辅助class:
@Serializable
data class VehicleDto(
val color: String,
val miles: Int,
val year: Int,
@Serializable(GarageToStringSerializer::class)
val garage: Garage
) {
constructor(v: Vehicle) : this(v.color, v.miles, v.year, v.garage)
}
可以通过以下方式接收要求的结果:
Json.encodeToString(VehicleDto(vehicle))
我有一个数据 class,它有一个 属性,其类型是另一个数据 class,像这样:
@Serializable
data class Vehicle (
val color: String,
val miles: Int,
val year: Int,
val garage: Garage
)
@Serializable
data class Garage (
val latitude: Float,
val longitude: Float,
val name: String
)
序列化后,它会产生如下输出:
{
"color" : "black" ,
"miles" : 35000 ,
"year" : 2017 ,
"garage" : { "latitude" : 43.478342 , "longitude" : -91.337000 , "name" : "Paul's Garage" }
}
但是我希望 garage
是其 JSON 表示的文字字符串,而不是实际的 JSON 对象。换句话说,期望的输出是:
{
"color" : "black" ,
"miles" : 35000 ,
"year" : 2017 ,
"garage" : "{ \"latitude\" : 43.478342 , \"longitude\" : -91.337000 , \"name\" : \"Paul's Garage\" }"
}
如何在 Kotlin 中完成此操作?仅需 kotlinx.serialization
即可完成还是绝对需要 Jackson/Gson?
请注意,此输出用于特定用途。我无法覆盖基本序列化程序,因为我仍然需要从正常的 JSON(第一个示例)中 serialize/deserialize。换句话说,最好的方案是将第一个 JSON 样本转换为第二个样本,而不一定要让数据 class 直接生成第二个样本。
谢谢!
为 Vehicle
创建自定义 SerializationStrategy
,如下所示:
val vehicleStrategy = object : SerializationStrategy<Vehicle> {
override val descriptor: SerialDescriptor
get() = buildClassSerialDescriptor("Vehicle") {
element<String>("color")
element<Int>("miles")
element<Int>("year")
element<String>("garage")
}
override fun serialize(encoder: Encoder, value: Vehicle) {
encoder.encodeStructure(descriptor) {
encodeStringElement(descriptor, 0, value.color)
encodeIntElement(descriptor, 1, value.miles)
encodeIntElement(descriptor, 2, value.year)
encodeStringElement(descriptor, 3, Json.encodeToString(value.garage))
}
}
}
然后传给Json.encodeToString()
:
val string = Json.encodeToString(vehicleStrategy, vehicle)
结果:
{"color":"black","miles":35000,"year":2017,"garage":"{\"latitude\":43.47834,\"longitude\":-91.337,\"name\":\"Paul's Garage\"}"}
更多信息here
这是一个解决方案,其中包含用于 Garage
的自定义序列化程序和用于 Vehicle
的附加 class。
Garage
到 String
序列化程序:
object GarageToStringSerializer : KSerializer<Garage> {
override val descriptor = PrimitiveSerialDescriptor("GarageToString", PrimitiveKind.STRING)
override fun serialize(encoder: Encoder, value: Garage) = encoder.encodeString(Json.encodeToString(value))
override fun deserialize(decoder: Decoder): Garage = Json.decodeFromString(decoder.decodeString())
}
辅助class:
@Serializable
data class VehicleDto(
val color: String,
val miles: Int,
val year: Int,
@Serializable(GarageToStringSerializer::class)
val garage: Garage
) {
constructor(v: Vehicle) : this(v.color, v.miles, v.year, v.garage)
}
可以通过以下方式接收要求的结果:
Json.encodeToString(VehicleDto(vehicle))