JSON1

JSON1 / JSON to Kotlin

JSON to Kotlin

Generate Kotlin data classes with kotlinx.serialization from a JSON sample. A SerialName annotation is added only where the JSON key differs from the property name.

Processed locally
InputJSON
Ready
OutputKotlin

Converted output appears here as you type.

Good to know

  • Every record in an array is inspected, not just the first, so a field that appears in only some of them is typed as optional rather than required.
  • Identical nested shapes are emitted once and reused, and reserved words are renamed to something legal in this language.

About this tool

A Kotlin data class gives you equals, hashCode, copy, and destructuring from the declaration alone, which is most of what a DTO needs. This generates one per object in the sample with kotlinx.serialization annotations, val throughout, and nested objects hoisted into classes of their own.

Kotlin's type system is the reason its output differs from the other JVM target here. Nullability is part of the type rather than a convention, so JSON's optionality maps onto it exactly:

  • LongEvery JSON integer, not Int. JSON has no width limit, and a 64-bit id from an API is common enough that narrowing by default would be the wrong bet.
  • DoubleAny number with a fractional part. Kotlin has no decimal type, so a monetary value needs BigDecimal and a custom serializer.
  • String?A nullable or sometimes-absent field. The question mark is enforced by the compiler, so the absent case cannot be forgotten the way it can in Java.
  • = nullOptional properties also get a default, which is what lets kotlinx.serialization accept a payload where the key is missing entirely rather than present and null.
  • Any?A field that was null in every record. Nothing narrower would be honest — replace it once you have a sample where the field is populated.
When is a SerialName annotation added?
Only when the JSON key differs from the property name after camelCasing — first_name becoming firstName needs one, title does not. Annotating everything would triple the length of a simple model for no gain.
Why kotlinx.serialization and not Moshi or Gson?
It is the JetBrains-maintained option and the only one that understands Kotlin nullability and default values without reflection. That matters specifically here: Gson constructs objects through Unsafe, so it will happily leave a non-null String holding null and the failure surfaces somewhere else entirely. Switching to Moshi means changing annotations, not the class.
Why is List<Any> a problem under @Serializable?
Because kotlinx.serialization needs a serializer for every type at compile time and Any has none. A heterogeneous or always-empty array produces one, and it will not compile until you either give the element a real type or register a contextual serializer. The generator emits it rather than guessing, so the gap is visible instead of silent.
Could these be value classes or a sealed hierarchy?
Not from a sample. A value class needs to know an id is semantically distinct from any other Long, and a sealed hierarchy needs to know which field discriminates the variants. Neither fact is in the JSON — they are decisions about your domain, and the data class is the honest starting point for both.
How are optional fields decided?
Every record in an array is inspected, not just the first. A field that appears in some records and not others is typed as optional, and a value that is sometimes null widens accordingly. Generators that read only the first element get this wrong on exactly the payloads where it matters.
What happens to a key that is a reserved word?
It is renamed to something legal in the target language, and where the language supports it, an annotation records the original JSON key so serialisation still round-trips.