Add option to encode only non-null default values in encodeDefaults
Currently, encodeDefaults = true writes all default values, while encodeDefaults = false omits all of them. There is no way to include only non-null defaults.
Motivation
In many API contexts, it is desirable to serialize default values that carry meaningful information but skip those that are null by default. This keeps payloads compact and avoids sending meaningless null entries while still preserving useful defaults.
@Serializable
data class UserProfile(
val id: String,
val nickname: String?,
val displayName: String? = null,
val country: String = "DE",
val avatarUrl: String? = null,
)
Rationale:
This would allow developers to keep meaningful defaults (like "DE") while automatically skipping null defaults, avoiding the need for custom serializers or post-processing.
Does
Json {
encodeDefaults = true
explicitNulls = false
}
achieve what you want?
~~Of course! Thanks!~~ ~~Didn't even try this combination. Just assumed that the default nulls are also serialized!~~
~~But of course it works.~~
I am wrong! It does not work in every case. I want to add "null" for all values that do not have a default value set.
Unfortunately I am not able to reopen the issue...
I want to add "null" for all values that do not have a default value set.
Isn't this what explicitNulls do?
during decoding, the absence of a field value is treated as null for nullable properties without a default value.
https://kotlinlang.org/api/kotlinx.serialization/kotlinx-serialization-json/kotlinx.serialization.json/-json-builder/explicit-nulls.html
The problem is my TypeScript client.
For TypeScript there are these possible types:
- Required (must be defined, must not be null)
- Optional (might be undefined - but not null)
- Nullable (might be null - but not undefined)
- Optional and Nullable (might be null or undefined).
Unfortunately I can not match these exact cases at the same time.
At the moment I have this mapping:
TS optional <-> Kotlin has default value TS nullable <-> Kotlin nullable TS optional + nullable <-> Kotlin nullable + has default value
Can you show the TS example, please?
Hi, @sandwwraith ! I encountered the same problem with:
- kotlinx-serialization-json v1.9.0
- kotlin v2.2.21
And I prepared a unit test for it:
import kotlinx.serialization.Serializable
import kotlinx.serialization.json.Json
import org.junit.jupiter.api.Assertions.assertEquals
import org.junit.jupiter.api.Test
class JsonTest {
private val GlobalJson = Json {
explicitNulls = true
encodeDefaults = true
}
@Serializable
data class TestData(
val name: String,
val data: String? = null,
)
@Test
fun json1() {
assertEquals(
"{\"name\":\"test\"}",
GlobalJson.encodeToString(TestData(
name = "test"
))
)
}
@Test
fun json2() {
assertEquals(
"{\"name\":\"test\"}",
GlobalJson.encodeToString(TestData(
name = "test",
data = null
))
)
}
}
Then I got the following result:
Expected :{"name":"test"}
Actual :{"name":"test","data":null}
Expected :{"name":"test"}
Actual :{"name":"test","data":null}
private val GlobalJson = Json { explicitNulls = true encodeDefaults = true }
This configuration means that the encoder should write both default values and null values, so the actual outputs are what should be expected. Would you mean to have explicitNulls = false?
Would you mean to have
explicitNulls = false?
Oh, thanks for the clarification. I completely misread the meaning of explicitNulls = true — I wasn’t paying enough attention and assumed it excluded nulls instead of outputting them.
That one’s on me. Thanks for pointing it out, and sorry for the noise. Everything makes sense now.