JSON to Kotlin Data Class
Generate Kotlin data classes for kotlinx.serialization from a JSON sample, with @Serializable and @SerialName. Every value is typed, and a key that some objects lack or hold as null is nullable.
About JSON to Kotlin
The objects in the JSON become Kotlin data classes for kotlinx.serialization. Each class is @Serializable, so Json.decodeFromString reads the JSON into it and Json.encodeToString writes it back, and a property whose name is not its key, such as createdAt for created_at, has a @SerialName with the key.
Every value at a place counts, not just the first. A number is an Int, a Long once one is beyond 32 bits, and a Double when one is written with a fraction or an exponent, as 10.0 and 1.5e3 are, since kotlinx.serialization reads neither as an Int. The objects at one place, such as the items of a list, make one class, with the keys in the order first seen. A key that is null in some objects is nullable, as in String?. One that some objects lack is nullable with a default of null, as in val coupon: String? = null, since kotlinx.serialization throws on an object that lacks a key whose property has no default.
kotlinx.serialization has no serializer for Any, so a key that holds two kinds of value, such as a string and a number, or only null, is a JsonElement, which holds any JSON as it is written, and objects that are always empty are a JsonObject. A note says why, as one does for each number a Double rounds and each null that is not written back.
Properties are lowerCamelCase, so user_id and userID both read as userId, and the second gets a number: userId2. A keyword such as class or val has Value added, and a class name that would hide a Kotlin type, such as List or Result, has Model added.
An object with so many keys that the JVM would not load its class, such as 246 that hold an Int or 125 that hold a Double, becomes a Map<String, T>, with a note. When the JSON is an array of objects, the class describes them, and a note gives the type that reads the whole array. Choose Every property to make every property nullable, with a default of null, for an API that can leave any key out. Everything runs in your browser.
For Dart, see JSON to Dart Class. For Java, try JSON to Java Class, and for Swift, JSON to Swift Struct.
Built and maintained by Meet Shah · Last updated
What this tool is used for
- Generating kotlinx.serialization models from an API response for an Android or Ktor app.
- Getting the
@SerialNameright for keys in snake_case, or with characters a Kotlin name cannot hold. - Producing a starting model for an endpoint with no published schema.
- Creating data classes for a test fixture that match production shapes.
- Seeing how a payload's nesting maps onto nested Kotlin classes.
Frequently Asked Questions
- How do JSON types map to Kotlin?
- Strings are
String, booleansBoolean, objects a data class and arrays aList. A number is anInt, aLongonce a sample is beyond 32 bits, and aDoublewhen a sample has a fraction or an exponent, as 10.0 and 1.5e3 do, or is an integer beyond aLong. A key null in some samples is nullable, as inString?. - Why is a property a JsonElement and not Any?
- kotlinx.serialization has no serializer for
Any, so it cannot read JSON into anAnyproperty. AJsonElementholds any JSON as it is written, so a key with two kinds of value, such as a string and a number, or only null, is one, and a note says why. Objects that are always empty are aJsonObject. - When is @SerialName written?
- Only where a property's name is not its key, as
createdAtis forcreated_at,classValueforclassandfield2Fafor2fa. kotlinx.serialization reads and writes a property under its own name unless a@SerialNamegives another, so each key is kept exactly as the JSON has it,$refandit'sincluded. - Why does a key some objects lack get = null?
- kotlinx.serialization throws a
MissingFieldExceptionon an object that lacks a key whose property has no default, so such a key is nullable with a default of null, as inval coupon: String? = null. A property that holds its default is left out when written back, so a null the JSON has there is not written back. - Why is an object sometimes a Map?
- kotlinx.serialization gives a class a constructor with a parameter per property and a few more, and JVM method parameters fill at most 255 slots, two for a
LongorDoublethat is not nullable. Past that the class compiles but does not load: 245Intproperties load, 246 do not. Such objects are aMap<String, T>. - Should every property be nullable?
- A sample shows only some of the keys an API can send as null or leave out: here a key that is null is nullable, and one that some objects lack also gets a default of null. The API contract says which others are. Every property makes them all nullable, each with a default of null, so a response can leave any key out.
Common errors and gotchas
- Trusting the nullability one sample shows: a key present in every object of the sample can still be left out of a real response, and kotlinx.serialization then throws a
MissingFieldException. Choose Every property when the API contract does not say. - Generating from a sample where a decimal field happens to hold a whole number, such as a price of 12: the property is typed
Int, and kotlinx.serialization then refuses 12.5. Use a sample with a fraction, or write 12.0. - Renaming a property without a
@SerialName: kotlinx.serialization reads and writes each property under its own name, so acreatedAtwith no annotation names no key the JSON has, and readingcreated_atinto it throws. - Naming a class after a type Kotlin already has, such as
List,MaporResult: the class hides Kotlin's type in its package, which is why a key namedlistgives a classListModelhere. - Sending an ID beyond the range of a Long as a JSON number: its property is a
Double, which holds integers exactly only up to 2^53, so the ID is rounded. Send such an ID as a string. - Expecting an unknown key to be skipped: kotlinx.serialization's default
Jsonthrows on a key the class has no property for, so a response that gains a field breaks the read. Build theJsonwithignoreUnknownKeys = truewhen the API can add fields.