Explain encodeDefaults and explicitNulls in the Json { } builder. How do they affect the JSON output for properties that equal their default or are null?
answer
- encodeDefaults: write values equal to default?
- explicitNulls: write nulls as key:null vs omit?
- both default-ish settings shrink JSON
- explicitNulls=false + default => decodes to default not null
- non-default value always emitted
basics
~10 sencodeDefaults decides whether properties equal to their default value are written out. explicitNulls decides whether nullable properties that are null are written as "key": null or omitted entirely.
solid answer
~40 sencodeDefaults (default false) controls properties that have a default value: when false, a property whose current value equals its declared default is omitted from the output to keep JSON compact; set true to always emit it. explicitNulls (default true) controls null handling: when true, a null nullable property is emitted as "key": null; when false, null values are omitted from output entirely, and on decoding a missing key falls back to the property's default (or null if there's no default — and if the property is non-null without a default you'd get an error). The two interact: a nullable property with a null default that is null gets omitted under either false setting. Use encodeDefaults=true when consumers need full payloads; use explicitNulls=false to produce patch-style/compact JSON where absence means 'unset'.
code
kotlin · 11 linesimport kotlinx.serialization.*
import kotlinx.serialization.json.*
@Serializable data class P(val a: Int?, val b: Int? = 7)
fun main() {
println(Json.encodeToString(P(null, null))) // {"a":null,"b":null}
val compact = Json { explicitNulls = false }
println(compact.encodeToString(P(null, null))) // {}
println(compact.decodeFromString<P>("{}")) // P(a=null, b=7)
}go deeper
Knows encodeDefaults controls writing default values and explicitNulls controls writing nulls.
Explains both flags, their defaults, and the omit-on-encode behavior with examples.
Nails the decode-side gotcha: omitted key + declared default decodes to the default, not null.
Reasons about payload contracts (full vs patch/compact), interop with consumers that distinguish null vs absent, and schema-evolution implications.
## encodeDefaults — emitting default values A `@Serializable` property can have a **default value** in its constructor. `encodeDefaults` controls whether such a property is written when its current value equals that default. - Default `false`: properties equal to their default are **omitted** (smaller payloads). - `true`: they are always written. ```kotlin @Serializable data class Cfg(val retries: Int = 3, val name: String = "x") Json.encodeToString(Cfg()) // {} — both at default, omitted Json { encodeDefaults = true }.encodeToString(Cfg()) // {"retries":3,"name":"x"} ``` A property whose value differs from its default is always emitted regardless of this flag. ## explicitNulls — emitting null values `explicitNulls` controls nullable properties whose value is `null`. - Default `true`: a null is written as `"key": null`. - `false`: null values are **omitted** from output. On **decoding**, a missing key is then filled from the property's default; if there is no default it becomes `null` (for a nullable type). ```kotlin @Serializable data class P(val a: Int?, val b: Int? = 7) Json.encodeToString(P(null, null)) // {"a":null,"b":null} val compact = Json { explicitNulls = false } compact.encodeToString(P(null, null)) // {} compact.decodeFromString<P>("{}") // P(a=null, b=7) ``` Note with `explicitNulls = false`, decoding `{}` sets `a` to `null` (no default, nullable) and `b` to its default `7` — *not* `null`. This is the classic gotcha: omitted-and-has-default decodes to the default, not null. ## How they differ - `encodeDefaults`: about values equal to a **declared default** (any type). - `explicitNulls`: specifically about **null** values of nullable properties. They are independent flags but both can cause a key to disappear. Use `encodeDefaults = true` for full, self-describing payloads; use `explicitNulls = false` for compact/patch-style JSON where 'missing means unset'.
- With explicitNulls = false, you decode {} into a class with val b: Int? = 7. What is b?7 — a missing key falls back to the declared default, not null. Only properties with no default become null.
- Does encodeDefaults affect properties whose value differs from the default?No. Such properties are always emitted; the flag only governs values that equal the default.
saying these in an interview costs you the question
- Confusing encodeDefaults with explicitNulls
- Claiming explicitNulls=false always decodes missing keys to null (it uses defaults when present)
- Saying default Json omits nulls (it doesn't; explicitNulls is true by default)
- Thinking encodeDefaults hides non-default values