Handling Nulls and Default Values

Moshi provides several ways to manage null values and properties that might be absent from the JSON.

Nullable Properties

By default, Moshi fully supports Kotlin's nullability system. If you declare a property as nullable (e.g., val name: String?), Moshi will correctly handle both null values and absent keys in the JSON.

@JsonClass(generateAdapter = true)
data class User(val name: String, val title: String?)
  • {"name":"Alice","title":"Engineer"} -> User(name="Alice", title="Engineer")
  • {"name":"Bob","title":null} -> User(name="Bob", title=null)
  • {"name":"Charlie"} -> User(name="Charlie", title=null)

If a non-nullable property is missing from the JSON or its value is null, Moshi will throw a JsonDataException.

Ignoring Properties

You can exclude properties from serialization and deserialization using @Json(ignore = true) or the transient keyword.

@JsonClass(generateAdapter = true)
data class User(
  val id: Long,
  @Json(ignore = true) var sessionToken: String? = null,
  @Transient var localCache: Any? = null
)
  • sessionToken and localCache will not be included in the output JSON.
  • If sessionToken or localCache keys are present in the input JSON, they will be ignored.
  • Properties that are ignored must have a default value if they are part of the primary constructor.

Serializing Nulls

By default, Moshi omits properties with null values from the output JSON. This is efficient and is standard practice for many APIs.

val user = User(id = 1, name = "Alice", title = null)

// Default behavior
moshi.adapter(User::class.java).toJson(user)
// Output: {"id":1,"name":"Alice"}

If you need to include nulls in the output, you can create a JsonAdapter with serializeNulls().

val user = User(id = 1, name = "Alice", title = null)

// With serializeNulls()
moshi.adapter(User::class.java).serializeNulls().toJson(user)
// Output: {"id":1,"name":"Alice","title":null}

Default Values

With Kotlin, Moshi honors default values declared in constructors. If a key is absent from the JSON, Moshi will use the property's default value.

@JsonClass(generateAdapter = true)
data class Player(
  val name: String,
  val score: Int = 0,          // Default value
  val isPro: Boolean = false   // Default value
)

When parsing JSON:

val json = """{"name":"jesse"}"""
val player = adapter.fromJson(json)
// player is Player(name="jesse", score=0, isPro=false)

This works seamlessly for both reflection and codegen-based adapters. If a key is present in the JSON, its value will be used, overriding the default.