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