Skip to content

JSON to Kotlin

Generate Kotlin data classes from a JSON sample.

Input

What this tool does

Generate Kotlin data class declarations from a JSON sample. val properties for immutable models, nullable types (String?) for fields the sample shows as null, and Gson @SerializedName annotations for JSON keys that aren’t valid Kotlin identifiers. Use the package option to set thepackage declaration. Powered by quicktype, runs entirely in your browser.

How to use it

Paste JSON (or load the example) and read the Kotlin data classes on the right. Set the package name in the options pane to match your module layout; default output uses Gson @SerializedName for JSON keys that aren’t valid Kotlin identifiers.

Input: {"id":42,"name":"devsmiths","createdAt":"2024-03-11T08:24:00Z","stars":1280,"public":true,"contributors":[{"login":"ada","commits":51,"admin":true},{"login":"linus","commits":33,"admin":false}],"homepage":null}

Output (Kotlin):

package com.devsmiths

import com.google.gson.annotations.SerializedName

data class Root(
    val id: Long,
    val name: String,
    @SerializedName("createdAt") val createdAt: String,
    val stars: Long,
    val public: Boolean,
    val contributors: List<Contributor>,
    val homepage: String?,
)

data class Contributor(
    val login: String,
    val commits: Long,
    val admin: Boolean,
)

Limits and edge cases

  • Output is data class with Gson @SerializedName. For kotlinx.serialization instead, replace @SerializedName with @SerialName, add @Serializable on each class, and import kotlinx.serialization.*.
  • Properties are val (immutable). For var properties (e.g. when wiring into Android DataBinding), change by hand — the generator favours immutability because most JSON DTOs should be read-only post-parse.
  • Nullable types use String? for fields containing null in the sample. Combine with a default value (val homepage: String? = null) to handle missing keys gracefully with both Gson and Moshi.
  • Whole numbers are Long regardless of magnitude. For smaller IDs use Int by hand; Gson and Moshi both decode either correctly. Floats default to Double.
  • Date strings stay as String, not java.time.Instant or kotlinx.datetime.Instant. Add a custom TypeAdapter (Gson) or KSerializer (kotlinx.serialization) for typed dates.
  • Single-sample inference: keys absent in the sample don’t become nullable. all optional flips every field to T? = null.

Frequently asked questions

Why Gson @SerializedName and not kotlinx.serialization?
Gson is still the most common JSON library on Android (it ships in many existing apps) and works on the JVM without further setup. kotlinx.serialization is excellent — strongly typed, multiplatform, KSP-driven — but requires adding the plugin to your build and `@Serializable` on each class. To switch: replace `@SerializedName("foo")` with `@SerialName("foo")`, add `@Serializable` on every class, and import `kotlinx.serialization.*`. The data class shapes are otherwise identical.
data class with val — but I need mutable fields. What now?
Change `val` to `var` per field by hand. The generator favours immutability because most JSON DTOs are read-only after parse — you mutate by `copy(fieldName = newValue)` instead of in-place mutation. For Android two-way DataBinding, you genuinely need var; flip the relevant fields.
How do I get null-safe deserialization for missing keys?
Combine nullable type with default: `val homepage: String? = null`. Both Gson and Moshi treat missing keys as null when the type is nullable and the default is provided. Without the default, a missing key throws on construction (Kotlin's null-safety prevents an uninitialized non-null property from existing). The 'all optional' toggle emits `= null` defaults on every nullable field.
Long vs Int — why Long for everything?
Same reason as Java: JSON numbers come through JavaScript as 64-bit doubles, so integers up to 2^53 are exact; beyond that you lose precision before the JSON reaches Kotlin. Long covers the safe range without surprise overflow. Tighten to Int by hand for IDs you know fit; Gson and Moshi tolerate either.
Can I use the generated data classes with Room / Realm?
Yes for Room with caveats. Room needs `@Entity` annotation and a no-arg constructor — data classes have one only if every property has a default. Add `@Entity` and provide defaults for non-nullable properties (`val id: Long = 0`) to satisfy Room. For Realm, the generated classes need to extend RealmObject and use `var` properties; use them as DTOs that you map into RealmObject equivalents.
How do I parse JSON into the generated data classes?
With Gson: `Gson().fromJson(jsonString, Root::class.java)`. With Moshi: `moshi.adapter(Root::class.java).fromJson(jsonString)`. With kotlinx.serialization (after the switch above): `Json.decodeFromString<Root>(jsonString)`. All three respect the annotations on the data class.

Content reviewed by