如何使用 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)