Kotlin Serialization

Programs keep data in objects. Files, databases, and web servers speak in plain text. Serialization converts an object into text so the data can travel or rest. Deserialization rebuilds the object from that text. The official library for this job is kotlinx.serialization.

Packing a Suitcase

Before a trip, you fold clothes and pack a suitcase. At the hotel, you unpack and hang everything again. Serialization is the packing step, and deserialization is the unpacking step. The most popular suitcase format is JSON, a simple text style with curly braces and quotes.

 Kotlin object              JSON text
 +----------------+        +----------------------------+
 | User           | pack   | {"name":"Asha","age":25}   |
 |  name = Asha   | -----> |                            |
 |  age  = 25     | <----- |                            |
 +----------------+ unpack +----------------------------+

Setup

The library needs a compiler plugin and a dependency in the Gradle file. Use the latest versions from the official documentation.

plugins {
    kotlin("plugin.serialization") version "2.0.0"
}

dependencies {
    implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.7.3")
}

Packing an Object

The label @Serializable marks a class as ready for packing. The function encodeToString produces the text.

import kotlinx.serialization.*
import kotlinx.serialization.json.*

@Serializable
data class User(val name: String, val age: Int)

fun main() {
    val user = User("Asha", 25)
    val text = Json.encodeToString(user)
    println(text)   // {"name":"Asha","age":25}
}

Unpacking Text

The function decodeFromString rebuilds the object. State the target type inside angle brackets.

val json = """{"name":"Ravi","age":31}"""
val user = Json.decodeFromString<User>(json)
println(user.name)   // Ravi

Lists and Nested Objects

Collections and objects inside objects work without extra effort, as long as every class carries the label.

@Serializable
data class Address(val city: String)

@Serializable
data class Person(val name: String, val address: Address, val tags: List<String>)

fun main() {
    val p = Person("Mina", Address("Pune"), listOf("admin", "editor"))
    println(Json.encodeToString(p))
    // {"name":"Mina","address":{"city":"Pune"},"tags":["admin","editor"]}
}

Renaming Fields

Servers often use names that differ from Kotlin style. The label @SerialName maps one to the other.

@Serializable
data class Product(
    @SerialName("product_name") val name: String,
    val price: Double
)

The JSON text uses product_name, and the Kotlin code uses name.

Default Values and Missing Data

A property with a default value may disappear from incoming text. The decoder fills the gap.

@Serializable
data class Settings(val theme: String = "light", val fontSize: Int = 14)

val s = Json.decodeFromString<Settings>("""{"fontSize":18}""")
println(s)   // Settings(theme=light, fontSize=18)

The encoder skips properties that equal their defaults, unless you turn on encodeDefaults.

Nullable Fields

@Serializable
data class Profile(val name: String, val nickname: String? = null)

Configuring Json

Create a custom Json instance to change behavior.

val format = Json {
    prettyPrint = true
    ignoreUnknownKeys = true
    encodeDefaults = true
}

println(format.encodeToString(User("Asha", 25)))
OptionEffect
prettyPrintAdds line breaks and indentation
ignoreUnknownKeysSkips fields the class does not know
encodeDefaultsWrites properties that hold default values
isLenientAccepts relaxed JSON, such as unquoted text

Handling Errors

Broken text or missing required fields throw a SerializationException.

try {
    Json.decodeFromString<User>("""{"name":"Asha"}""")
} catch (e: SerializationException) {
    println("Bad data")
}

Servers add new fields over time. The option ignoreUnknownKeys keeps old apps working.

Round Trip Check

val original = User("Asha", 25)
val copy = Json.decodeFromString<User>(Json.encodeToString(original))
println(original == copy)   // true

A data class compares by content, so the check returns true.

Where This Fits

 Web server --JSON text--> decodeFromString --> Kotlin objects
 Kotlin objects --encodeToString--> JSON text --> File or server