如何使用 kotlin 序列化防止序列化空值
How to prevent serializing null values using kotlin serialization
我正在使用 kotlinx-serialization-json
我有这个class:
@Serializable
data class Event(
@SerialName("temperature") val temperature: Float?,
@SerialName("pressure") val pressure: Float?,
@SerialName("humidity") val humidity: Float?,
)
和这个电话
Json.encodeToString(Event(temperature = 42.0f, pressure = null, humidity = 20.9f))
在连载期间我收到这样的 json:
{
"temperature": 20.5,
"pressure": null,
"humidity": 20.9
}
但我想防止序列化空值并收到此消息:
{
"temperature": 20.5,
"humidity": 20.9
}
这对我来说是个问题,因为在序列化冗长的事件列表时我浪费了很多行。有人知道如何实现这一点吗?
编辑:
有一种新的简单方法可以实现这一点:
https://blog.jetbrains.com/kotlin/2021/09/kotlinx-serialization-1-3-released/#excluding-nulls
您可以忽略所有默认值并执行如下操作:
@Serializable
data class Event(
@SerialName("temperature") val temperature: Float?,
@SerialName("pressure") val pressure: Float? = null,
@SerialName("humidity") val humidity: Float?,
)
val jsonMapper = Json { encodeDefaults = false}
val body = jsonMapper.encodeToString(Event(temperature = 42.0f,pressure = null, humidity = 20.9f))
请注意,在上述情况下,您忽略了所有默认值。
如果您只想忽略空值,则必须实现自定义序列化程序。
对于此示例,自定义序列化程序将如下所示:
object EventSerializer: KSerializer<Event> {
override fun deserialize(decoder: Decoder): Event {
decoder.decodeStructure(descriptor) {
var temperature: Float? = null
var humidity:Float? = null
var pressure: Float? = null
while (true) {
when (val index = decodeElementIndex(descriptor)) {
0 -> temperature = decodeFloatElement(descriptor, 0)
1 -> pressure = decodeFloatElement(descriptor, 1)
2 -> humidity = decodeFloatElement(descriptor, 2)
CompositeDecoder.DECODE_DONE -> break
else -> error("Unexpected index: $index")
}
}
return Event(temperature, pressure, humidity)
}
}
override fun serialize(encoder: Encoder, value: Event) {
encoder.beginStructure(descriptor).run {
value.temperature?.let { encodeStringElement(descriptor, 0, it.toString()) }
value.pressure?.let { encodeStringElement(descriptor, 1, it.toString()) }
value.humidity?.let { encodeStringElement(descriptor, 2, it.toString()) }
endStructure(descriptor)
}
}
override val descriptor: SerialDescriptor = buildClassSerialDescriptor("Event") {
element<String>("temperature")
element<String>("pressure")
element<String>("humidity")
}
}
使用它 -> @Serializable(with = EventSerializer::class)
我正在使用 kotlinx-serialization-json
我有这个class:
@Serializable
data class Event(
@SerialName("temperature") val temperature: Float?,
@SerialName("pressure") val pressure: Float?,
@SerialName("humidity") val humidity: Float?,
)
和这个电话
Json.encodeToString(Event(temperature = 42.0f, pressure = null, humidity = 20.9f))
在连载期间我收到这样的 json:
{
"temperature": 20.5,
"pressure": null,
"humidity": 20.9
}
但我想防止序列化空值并收到此消息:
{
"temperature": 20.5,
"humidity": 20.9
}
这对我来说是个问题,因为在序列化冗长的事件列表时我浪费了很多行。有人知道如何实现这一点吗?
编辑:
有一种新的简单方法可以实现这一点: https://blog.jetbrains.com/kotlin/2021/09/kotlinx-serialization-1-3-released/#excluding-nulls
您可以忽略所有默认值并执行如下操作:
@Serializable
data class Event(
@SerialName("temperature") val temperature: Float?,
@SerialName("pressure") val pressure: Float? = null,
@SerialName("humidity") val humidity: Float?,
)
val jsonMapper = Json { encodeDefaults = false}
val body = jsonMapper.encodeToString(Event(temperature = 42.0f,pressure = null, humidity = 20.9f))
请注意,在上述情况下,您忽略了所有默认值。 如果您只想忽略空值,则必须实现自定义序列化程序。
对于此示例,自定义序列化程序将如下所示:
object EventSerializer: KSerializer<Event> {
override fun deserialize(decoder: Decoder): Event {
decoder.decodeStructure(descriptor) {
var temperature: Float? = null
var humidity:Float? = null
var pressure: Float? = null
while (true) {
when (val index = decodeElementIndex(descriptor)) {
0 -> temperature = decodeFloatElement(descriptor, 0)
1 -> pressure = decodeFloatElement(descriptor, 1)
2 -> humidity = decodeFloatElement(descriptor, 2)
CompositeDecoder.DECODE_DONE -> break
else -> error("Unexpected index: $index")
}
}
return Event(temperature, pressure, humidity)
}
}
override fun serialize(encoder: Encoder, value: Event) {
encoder.beginStructure(descriptor).run {
value.temperature?.let { encodeStringElement(descriptor, 0, it.toString()) }
value.pressure?.let { encodeStringElement(descriptor, 1, it.toString()) }
value.humidity?.let { encodeStringElement(descriptor, 2, it.toString()) }
endStructure(descriptor)
}
}
override val descriptor: SerialDescriptor = buildClassSerialDescriptor("Event") {
element<String>("temperature")
element<String>("pressure")
element<String>("humidity")
}
}
使用它 -> @Serializable(with = EventSerializer::class)