By default kotlinx.serialization treats a property with a default value as optional during decoding. How does @Required change that, and when would you use it?
answer
- Default value => optional on decode; @Required undoes that
- Missing required key => MissingFieldException
- Affects decoding only, not encoding
- Orthogonal to encodeDefaults / @EncodeDefault
- Redundant on a property that has no default
basics
~20 sProperties with a default value can be left out of the JSON and the default fills in. @Required forces that property to be present in the input even though it has a default — decoding fails if it's missing.
solid answer
~50 sIn kotlinx.serialization, a property WITHOUT a default value is always mandatory in the input; a property WITH a default value is OPTIONAL — if the key is absent the default is used. @Required overrides that for a defaulted property: it makes the key mandatory in the encoded input again, so a missing key throws MissingFieldException during decoding even though a default exists. Use it when you want a default in code (e.g. for construction/tests) but want to guarantee callers actually send the value over the wire — catching truncated or partial payloads. It only affects DECODING strictness; it has no effect on encoding. It is independent of encodeDefaults — that controls whether defaults are written out, while @Required controls whether absence on input is tolerated. @Required on a property that has no default is redundant (it's already required).
code
kotlin · 8 lines@Serializable
data class Payment(
val amount: Int,
@Required val currency: String = "USD", // default for code, mandatory on wire
)
Json.decodeFromString<Payment>("""{"amount":10}""")
// throws MissingFieldException: currencygo deeper
Knows defaulted fields can be omitted from JSON and the default fills in.
Explains @Required re-mandates a defaulted field on input and that missing keys throw MissingFieldException.
Separates the three axes (encode default / require on input / transient) and discusses round-trip risks combining @Required with encodeDefaults=false.
Designs API contracts using @Required to detect truncated payloads while keeping ergonomic constructors, weighing forward/backward compatibility.
## The default-value rule kotlinx.serialization decides optionality from whether a property has a **default value**: - **No default** -> the property is **required** in the input. Missing key => `MissingFieldException`. - **Has a default** -> the property is **optional**. Missing key => the default is substituted, no error. ```kotlin @Serializable data class Config( val host: String, // required (no default) val port: Int = 8080, // optional (default) ) Json.decodeFromString<Config>("""{"host":"a"}""") // ok, port = 8080 Json.decodeFromString<Config>("""{"port":1}""") // MissingFieldException: host ``` ## What @Required does `@Required` makes a **defaulted** property mandatory in the input again — you keep the default for in-code construction but force the wire to carry it: ```kotlin @Serializable data class Config( val host: String, @Required val port: Int = 8080, // default kept, but input MUST contain it ) Json.decodeFromString<Config>("""{"host":"a"}""") // MissingFieldException: Field 'port' is required ``` So the default still works when you call `Config("a")` in Kotlin, but a JSON payload without `port` is rejected. This is useful for **catching truncated/partial payloads** or enforcing an explicit-contract API while keeping ergonomic constructors and test fixtures. ## What it does NOT affect - **Encoding.** `@Required` only changes **decoding** strictness. It never changes what is written. - **encodeDefaults.** That JSON setting (and `@EncodeDefault`) controls whether default-valued properties are **written out**. `@Required` controls whether their **absence on input** is tolerated. They are orthogonal: - `encodeDefaults = false` + `@Required` is a sensible combo only with care — you might omit it on encode yet require it on decode, which can break round-tripping. Usually pair `@Required` with encoding the value. - **Properties without a default.** Those are already required; `@Required` is redundant there. ## Mental model Think of three independent switches on a defaulted property: 1. Is it written out? -> `@EncodeDefault` / `encodeDefaults`. 2. May it be omitted from input? -> `@Required` (no = must be present). 3. Is it on the wire at all? -> `@Transient` removes it entirely. ## Gotcha `Json { ignoreUnknownKeys = ... }` is about **extra** keys; `@Required` is about **missing** keys — different axes.
- Does @Required affect what gets written during encoding?No, it only makes the key mandatory during decoding; encoding behavior is unchanged.
- Is @Required meaningful on a property that has no default value?No — a property without a default is already required, so @Required is redundant there.
A form field pre-filled with a suggested value (default) that is still marked with a red asterisk (@Required) — you can prefill, but you must not leave it blank when submitting.
saying these in an interview costs you the question
- Saying @Required forces the value to be encoded (it affects decode only)
- Confusing @Required with ignoreUnknownKeys (missing vs extra keys)
- Thinking properties without defaults are optional by default
- Believing @Required removes the default value
- Conflating @Required with @EncodeDefault