Skip to content

JSON to Kotlin Data Class

Convert JSON to Kotlin data classes for kotlinx.serialization, ready for Json.decodeFromString on Android, the JVM or Multiplatform.

Input · JSON
Output · Kotlin
Valid JSONRuns in your browser

Load from a URL

Your browser fetches it directly, so the server must allow cross-origin requests (CORS).

JSON to Kotlin data class example

With Profile as the Root name, the sample user profile becomes:

{
  "userId": "u-7781",
  "displayName": "Noor",
  "avatar": {
    "url": "https://cdn.example.com/a/7781.png",
    "width": 256,
    "height": 256
  },
  "settings": {
    "darkMode": true,
    "language": "ar",
    "notifications": { "push": true, "email": false }
  },
  "badges": ["early-adopter", "reviewer"]
}
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable

@Serializable
data class Profile(
    @SerialName("userId") val userId: String,
    @SerialName("displayName") val displayName: String,
    @SerialName("avatar") val avatar: Avatar,
    @SerialName("settings") val settings: Settings,
    @SerialName("badges") val badges: List<String>,
)

@Serializable
data class Settings(
    @SerialName("darkMode") val darkMode: Boolean,
    @SerialName("language") val language: String,
    @SerialName("notifications") val notifications: Notifications,
)

@Serializable
data class Notifications(
    @SerialName("push") val push: Boolean,
    @SerialName("email") val email: Boolean,
)

@Serializable
data class Avatar(
    @SerialName("url") val url: String,
    @SerialName("width") val width: Long,
    @SerialName("height") val height: Long,
)

Each object is a data class with val properties, so instances are immutable and compare by value. Whole numbers are Long, since a sample can’t show whether a value will outgrow Int, and a value too large for Int fails to decode. @SerialName sits on every property, even where it matches the key, so you can rename userId to id without breaking decoding. It also maps a snake_case key such as avatar_url to the camelCase property avatarUrl.

Nullable, optional and mixed values

Array items are merged before typing (rules on JSON to TypeScript). With Results as the root name:

[
  { "player": "noor", "score": 1200 },
  { "player": "kai", "score": "DNF", "team": "red" }
]
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
import kotlinx.serialization.json.JsonElement

@Serializable
data class Result(
    @SerialName("player") val player: String,
    @SerialName("score") val score: JsonElement,
    @SerialName("team") val team: String? = null,
)

team is missing from the first item, so it is String? = null. The default is what makes the key optional: kotlinx.serialization requires every property without a default, even a nullable one. score was a number in one item and a string in the other, so it is a JsonElement; read it with score.jsonPrimitive.content, or .longOrNull for the number.

Setup and decoding

Apply the serialization compiler plugin (kotlin("plugin.serialization") in Gradle, at your Kotlin version) and add org.jetbrains.kotlinx:kotlinx-serialization-json. Without the plugin, @Serializable does nothing and decoding fails at runtime for lack of a serializer.

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

val json = Json { ignoreUnknownKeys = true }

fun parseProfile(body: String): Profile = json.decodeFromString<Profile>(body)

The default Json throws on undeclared keys, so ignoreUnknownKeys = true keeps older app versions working when the API adds a field. When encoding, properties still at their null default are left out unless you set encodeDefaults = true. The same json instance plugs into Ktor’s ContentNegotiation plugin and Retrofit’s kotlinx.serialization converter.

For the iOS and Flutter sides, JSON to Swift and JSON to Dart build matching models.

Questions

Does it work with Moshi or Gson?

Not without edits, because the annotations come from kotlinx.serialization. Moshi uses @Json(name = "key") and Gson uses @SerializedName("key") for the same job.

Can I use the classes in Kotlin Multiplatform?

Yes. kotlinx.serialization runs on every Kotlin target and the generated classes use nothing platform-specific, so they can live in commonMain.

Do non-null lists get a default value?

No. Only nullable properties get = null. If a list can be missing from the JSON, add = emptyList() yourself, or decoding fails for that key.

Related tools

Esc