Question
I am receiving a deeply nested JSON string from a service, and I need to parse it into a JSON object and then map it to Kotlin classes.
How can I convert a JSON string into an object in Kotlin?
After that, I need to map the parsed data to the appropriate classes. I was previously using StdDeserializer from Jackson, but I ran into problems when some properties also needed to be deserialized into custom classes. I did not know how to access or reuse the object mapper inside another deserializer.
Preferably, I would like a solution with minimal dependencies. If the answer focuses only on JSON parsing and manipulation, that would still be enough.
Short Answer
By the end of this page, you will understand how JSON parsing works in Kotlin, how to turn a JSON string into structured objects, and how to map nested JSON into Kotlin data classes. You will also see when to use manual parsing versus automatic mapping, and how common libraries such as Jackson or kotlinx.serialization help with nested objects.
Concept
JSON parsing in Kotlin usually means one of two things:
- Reading raw JSON data so you can inspect keys and values
- Mapping JSON directly into Kotlin classes so you can work with typed objects
A JSON string is just text until a parser reads it and turns it into a structure your program understands.
For example, this JSON:
{
"name": "Ada",
"age": 31
}
can be treated as:
- a generic JSON object with keys like
nameandage, or - a Kotlin class such as:
data class User(val name: String, val age: Int)
In real Kotlin projects, developers usually prefer mapping JSON straight into data classes because:
- the code becomes safer and easier to read
- nested JSON can become nested Kotlin objects
- the compiler helps catch mistakes
- you avoid lots of manual key lookups
If your JSON is deeply nested, manual parsing becomes tedious very quickly. That is why JSON libraries are commonly used.
Mental Model
Think of a JSON string as a packed delivery box with labels.
- Parsing JSON means opening the box and reading what is inside.
- Mapping JSON to Kotlin classes means placing each item into the correct shelf or container.
If the box contains another box inside it, that is like a nested JSON object. Your Kotlin class can also contain another class to match that structure.
For example:
- outer JSON object → outer Kotlin data class
- nested JSON object → nested Kotlin data class
- JSON array → Kotlin
List
If your shelves are labeled correctly, the library can often put everything in the right place automatically.
Syntax and Examples
Parsing and mapping with kotlinx.serialization
A common Kotlin-first solution is kotlinx.serialization.
import kotlinx.serialization.Serializable
import kotlinx.serialization.json.Json
@Serializable
data class Address(
val city: String,
val zip: String
)
@Serializable
data class User(
val name: String,
val age: Int,
val address: Address
)
fun main() {
val jsonString = """
{
"name": "Ada",
"age": 31,
"address": {
"city": "London",
"zip": "SW1"
}
}
""".trimIndent()
val user = Json.decodeFromString<User>(jsonString)
println(user)
println(user.address.city)
}
What this does
@Serializabletells Kotlin how to encode and decode the class.Json.decodeFromString<User>(jsonString)parses the JSON string.- The nested object is automatically mapped to the class.
Step by Step Execution
Consider this Kotlin code:
import kotlinx.serialization.Serializable
import kotlinx.serialization.json.Json
@Serializable
data class Profile(val username: String)
@Serializable
data class Account(val id: Int, val profile: Profile)
fun main() {
val jsonString = """
{
"id": 10,
"profile": {
"username": "kotlin_dev"
}
}
""".trimIndent()
val account = Json.decodeFromString<Account>(jsonString)
println(account)
}
Step by step
-
The program defines two data classes:
ProfileAccount
-
Accountcontains a property namedprofileof typeProfile. -
The JSON string contains:
Real World Use Cases
JSON parsing in Kotlin is used in many common situations:
API responses
A mobile app or backend service receives JSON from a REST API and maps it to data classes.
data class Product(val id: Int, val name: String, val price: Double)
Configuration files
An application reads JSON configuration at startup.
Examples:
- feature flags
- API endpoints
- environment settings
Caching remote data
A service fetches JSON once, saves it, and loads it later into classes.
Event processing
A queue or webhook sends JSON payloads that must be validated and transformed into domain objects.
Partial JSON inspection
Sometimes you only need one field from a large payload, such as:
- status
- error message
- token
In that case, raw JSON parsing can be enough without mapping the full structure.
Real Codebase Usage
In real projects, developers usually choose one of these patterns:
1. Map directly to data classes
This is the most common pattern when the JSON schema is known.
@Serializable
data class ApiResponse(val success: Boolean, val data: User)
This keeps application code clean and type-safe.
2. Use nested classes to match nested JSON
If the JSON contains objects inside objects, developers define nested models.
data class Order(val id: String, val customer: Customer)
data class Customer(val name: String, val email: String)
3. Use nullable properties for optional fields
Real APIs often omit fields.
@Serializable
data class User(
val name: String,
val nickname: String? = null
)
Common Mistakes
1. Expecting Kotlin standard library to parse JSON by itself
Kotlin does not include a full JSON parser in the standard library.
You usually need a library such as kotlinx.serialization, Jackson, Gson, or Moshi.
2. Class structure does not match JSON structure
Broken example:
data class User(val name: String, val city: String)
But the JSON is:
{
"name": "Ada",
"address": {
"city": "London"
}
}
This will not map correctly because city is nested inside address.
Correct version:
data class Address(val city: String)
( name: String, address: Address)
Comparisons
| Approach | Best for | Pros | Cons |
|---|---|---|---|
| Raw JSON parsing | Inspecting a few fields or dynamic JSON | Flexible, no need for many classes | More manual work, less type safety |
| Mapping to data classes | Known API responses | Clean, type-safe, easier to maintain | Requires matching class definitions |
| Custom deserializer | Special or inconsistent formats | Handles unusual data shapes | More code, harder to maintain |
kotlinx.serialization vs Jackson
| Library | Strengths | Considerations |
|---|---|---|
kotlinx.serialization | Kotlin-first, concise, good for data classes |
Cheat Sheet
Quick reference
Parse JSON to Kotlin object with kotlinx.serialization
@Serializable
data class User(val name: String)
val user = Json.decodeFromString<User>(jsonString)
Parse JSON as raw JSON tree
val element = Json.parseToJsonElement(jsonString)
Access a field from a JSON object
val name = element.jsonObject["name"]?.jsonPrimitive?.content
Nested object mapping
@Serializable
data class Address(val city: String)
@Serializable
data class User(val name: String, val address: Address)
Ignore unknown fields
val json = Json {
ignoreUnknownKeys =
}
FAQ
Can Kotlin parse JSON without a library?
Not fully with the standard library alone. In practice, you use a JSON library such as kotlinx.serialization, Jackson, Gson, or Moshi.
What is the easiest way to map JSON to Kotlin classes?
For Kotlin projects, kotlinx.serialization is often the simplest and most Kotlin-friendly option. If your project already uses Jackson, it is also a strong choice.
How do I parse nested JSON in Kotlin?
Create nested data classes that match the JSON structure. The parser can then map inner JSON objects to inner Kotlin objects automatically.
Do I need a custom deserializer for nested objects?
Usually no. If your JSON structure matches your Kotlin classes, most libraries handle nested objects automatically.
How can I read only one field from a JSON string?
Parse the JSON as a raw JSON element or object, then extract the key you need instead of mapping the whole payload.
What if the API returns extra fields I do not need?
Configure the parser to ignore unknown fields, or use a library setting that skips unused properties.
Why does my JSON mapping fail in Kotlin?
Common reasons include mismatched property names, wrong data types, missing annotations, nullability issues, or a class structure that does not match the JSON.
Mini Project
Description
Build a small Kotlin program that reads a nested JSON response representing a blog post and converts it into Kotlin data classes. This demonstrates how nested JSON objects can be mapped directly without manually extracting every field.
Goal
Parse a nested JSON string into Kotlin objects and print selected values from the mapped result.
Requirements
- Create Kotlin data classes for a blog post, author, and metadata.
- Use a JSON string that contains nested objects.
- Parse the JSON string into Kotlin objects.
- Print the post title, author name, and view count.
- Keep the solution focused on parsing and mapping, not networking.
Keep learning
Related questions
Accessing Kotlin Extension Functions from Java
Learn how Kotlin extension functions are compiled and how to call them correctly from Java with clear examples and common pitfalls.
Allow HTTP and HTTPS in Android 9 Pie with Network Security Configuration
Learn how Android 9 Pie handles cleartext HTTP traffic and how to allow HTTP and HTTPS safely using network security config.
Android AlarmManager Example: Scheduling Tasks with AlarmManager
Learn how to use Android AlarmManager to schedule tasks, set alarms, and handle broadcasts with a simple beginner example.