Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to prevent serializing null values using kotlin serialization

I'm using kotlinx-serialization-json

I have this class:

@Serializable
data class Event(
    @SerialName("temperature") val temperature: Float?,
    @SerialName("pressure") val pressure: Float?,
    @SerialName("humidity") val humidity: Float?,
)

and this call

Json.encodeToString(Event(temperature = 42.0f, pressure = null, humidity = 20.9f))

During serialization I receive such json:

{
    "temperature": 20.5,
    "pressure": null,
    "humidity": 20.9
}

but I would like to prevent serializing null values and receive this:

{
    "temperature": 20.5,
    "humidity": 20.9
}

It's a problem for me, because during serializing lengthy list of events I waste a lot of lines. Anyone's got an idea how to achieve this?

EDIT:

There is new simple way to achieve this: https://blog.jetbrains.com/kotlin/2021/09/kotlinx-serialization-1-3-released/#excluding-nulls

like image 450
Krystian Kaniowski Avatar asked Jun 18 '26 17:06

Krystian Kaniowski


1 Answers

You can ignore all defaults and do something like this:

@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))

Please, be aware of that, in the above case you are ignoring ALL defaults. If you want to ignore only null values you have to implement a custom serializer.

For this example custom serializer will look like this:


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")

    }
}

To use it -> @Serializable(with = EventSerializer::class)

like image 131
Ice Avatar answered Jun 20 '26 06:06

Ice



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!