JSON Parsing

Convert between JSON strings and Kotlin objects for API responses and local storage

Objects Arrays Gson Serialize

Table of Contents

JSON Overview

JSON (JavaScript Object Notation) is the standard data format for REST APIs. Android apps receive JSON as text and must parse it into Kotlin objects to display in the UI or store locally.

API Response (JSON String) ↓ Parsing / Deserialization ↓ Kotlin Data Classes ↓ UI (RecyclerView, TextView, etc.)
JSON TypeKotlin TypeExample
Object { }data class{"name": "Nikhil"}
Array [ ]List<T>[1, 2, 3]
StringString"hello"
NumberInt / Double42, 3.14
BooleanBooleantrue
nullnullable typenull

1JSON Objects

A JSON object is a collection of key-value pairs wrapped in curly braces { }. Keys are always strings; values can be strings, numbers, booleans, null, arrays, or nested objects.

Simple object example

JSON — User object{ "id": 1, "name": "Nikhil Kumar", "email": "nikhil@example.com", "isActive": true, "avatarUrl": null }

Matching Kotlin data class

Kotlin — User.ktdata class User( val id: Int, val name: String, val email: String, val isActive: Boolean, val avatarUrl: String? = null )

Nested object

JSON — Nested address{ "id": 1, "name": "Nikhil", "address": { "street": "123 Main St", "city": "Hyderabad", "zipCode": "500001" } }
Kotlin — Nested data classesdata class User( val id: Int, val name: String, val address: Address ) data class Address( val street: String, val city: String, val zipCode: String )

Access with org.json.JSONObject

Kotlin — Read object fields manuallyval jsonString = """{"id":1,"name":"Nikhil","email":"nikhil@example.com"}""" val jsonObject = JSONObject(jsonString) val id = jsonObject.getInt("id") val name = jsonObject.getString("name") val email = jsonObject.optString("email", "") // safe — returns default if missing // Nested object val addressObj = jsonObject.getJSONObject("address") val city = addressObj.getString("city")

2JSON Arrays

A JSON array is an ordered list of values wrapped in square brackets [ ]. Arrays commonly hold lists of objects — such as posts, users, or products from an API.

Array of primitives

JSON — String array["Android", "Kotlin", "Java", "Compose"]

Array of objects

JSON — Posts array[ { "id": 1, "title": "First Post", "body": "Hello JSON!" }, { "id": 2, "title": "Second Post", "body": "Learning arrays." } ]
Kotlin — List of data classdata class Post( val id: Int, val title: String, val body: String ) // Type: List<Post>

Access with org.json.JSONArray

Kotlin — Loop through JSONArrayval jsonArray = JSONArray(jsonString) val posts = mutableListOf<Post>() for (i in 0 until jsonArray.length()) { val obj = jsonArray.getJSONObject(i) posts.add( Post( id = obj.getInt("id"), title = obj.getString("title"), body = obj.getString("body") ) ) }

Mixed structure — object containing array

JSON — Wrapper with data array{ "status": "success", "count": 2, "data": [ { "id": 1, "name": "Item A" }, { "id": 2, "name": "Item B" } ] }

3Parsing JSON

Parsing JSON means reading a JSON string and extracting structured data. Android provides built-in org.json classes, or you can use libraries like Gson for automatic mapping.

Manual parsing — complete example

Kotlin — JsonParser.ktobject JsonParser { fun parseUser(jsonString: String): User? { return try { val obj = JSONObject(jsonString) User( id = obj.getInt("id"), name = obj.getString("name"), email = obj.getString("email"), isActive = obj.optBoolean("isActive", true), avatarUrl = obj.optString("avatarUrl").ifEmpty { null } ) } catch (e: JSONException) { Log.e("JsonParser", "Failed to parse user", e) null } } fun parsePostList(jsonString: String): List<Post> { val posts = mutableListOf<Post>() try { val array = JSONArray(jsonString) for (i in 0 until array.length()) { val obj = array.getJSONObject(i) posts.add( Post( id = obj.getInt("id"), title = obj.getString("title"), body = obj.getString("body") ) ) } } catch (e: JSONException) { Log.e("JsonParser", "Failed to parse posts", e) } return posts } fun parseApiResponse(jsonString: String): ApiResponse? { return try { val root = JSONObject(jsonString) val dataArray = root.getJSONArray("data") val items = mutableListOf<Item>() for (i in 0 until dataArray.length()) { val obj = dataArray.getJSONObject(i) items.add(Item(id = obj.getInt("id"), name = obj.getString("name"))) } ApiResponse( status = root.getString("status"), count = root.getInt("count"), data = items ) } catch (e: JSONException) { null } } } data class ApiResponse(val status: String, val count: Int, val data: List<Item>) data class Item(val id: Int, val name: String)

Parse from assets or raw resource

Kotlin — Read JSON from assetsfun Context.readJsonFromAssets(fileName: String): String { return assets.open(fileName).bufferedReader().use { it.readText() } } // Usage in Activity: val jsonString = readJsonFromAssets("posts.json") val posts = JsonParser.parsePostList(jsonString)

When to parse manually vs use a library

ApproachBest For
org.json (manual)Simple objects, learning, no extra dependency
Gson / MoshiComplex models, Retrofit integration, production apps

4Gson Library

Gson is Google's library for converting between JSON and Kotlin/Java objects. It is widely used with Retrofit and removes the need for manual JSONObject/JSONArray loops.

Gradle dependency

Kotlin — app/build.gradle.ktsdependencies { implementation("com.google.code.gson:gson:2.10.1") }

Basic Gson usage

Kotlin — GsonHelper.ktobject GsonHelper { private val gson = Gson() fun fromJson(json: String): User { return gson.fromJson(json, User::class.java) } fun fromJsonList(json: String): List<Post> { val type = object : TypeToken<List<Post>>() {}.type return gson.fromJson(json, type) } fun toJson(user: User): String { return gson.toJson(user) } }

Field name mapping with @SerializedName

Kotlin — Map snake_case JSON to camelCasedata class Product( val id: Int, val name: String, @SerializedName("unit_price") val unitPrice: Double, @SerializedName("in_stock") val inStock: Boolean ) // JSON: {"id":1,"name":"Phone","unit_price":999.99,"in_stock":true}

Custom Gson instance with options

Kotlin — GsonBuilder configurationval gson = GsonBuilder() .setLenient() // allow malformed JSON .serializeNulls() // include null fields in output .setDateFormat("yyyy-MM-dd'T'HH:mm:ss") // parse date strings .create()

Retrofit integration

Kotlin — Retrofit with GsonConverterFactoryRetrofit.Builder() .baseUrl("https://jsonplaceholder.typicode.com/") .addConverterFactory(GsonConverterFactory.create()) .build() .create(ApiService::class.java) // Retrofit automatically deserializes JSON response → List<Post>

5Serialization & Deserialization

Deserialization converts JSON → Kotlin object (reading/parsing). Serialization converts Kotlin object → JSON string (writing/saving). Both directions are essential for API calls and local caching.

Deserialization (JSON → Object) Serialization (Object → JSON) ───────────────────────────────── ───────────────────────────────── API response body POST request body SharedPreferences cache Save to file / Room Read from assets Export / debug logging

Deserialization — JSON to object

Kotlin — Deserialize with Gsonval json = """{"id":1,"name":"Nikhil","email":"nikhil@example.com","isActive":true}""" // Single object val user: User = Gson().fromJson(json, User::class.java) // List of objects val postsJson = """[{"id":1,"title":"Hello","body":"World"}]""" val type = object : TypeToken<List<Post>>() {}.type val posts: List<Post> = Gson().fromJson(postsJson, type)

Serialization — object to JSON

Kotlin — Serialize with Gsonval user = User(id = 1, name = "Nikhil", email = "nikhil@example.com", isActive = true) val jsonString = Gson().toJson(user) // Output: {"id":1,"name":"Nikhil","email":"nikhil@example.com","isActive":true,...} // Pretty-print for debugging val prettyJson = GsonBuilder().setPrettyPrinting().create().toJson(user)

Save and load with SharedPreferences

Kotlin — Cache user as JSONclass UserCache(context: Context) { private val prefs = context.getSharedPreferences("user_cache", Context.MODE_PRIVATE) private val gson = Gson() fun saveUser(user: User) { prefs.edit().putString("user_json", gson.toJson(user)).apply() } fun loadUser(): User? { val json = prefs.getString("user_json", null) ?: return null return gson.fromJson(json, User::class.java) } fun savePostList(posts: List<Post>) { prefs.edit().putString("posts_json", gson.toJson(posts)).apply() } fun loadPostList(): List<Post> { val json = prefs.getString("posts_json", null) ?: return emptyList() val type = object : TypeToken<List<Post>>() {}.type return gson.fromJson(json, type) } }

Write JSON to internal storage file

Kotlin — Save JSON to filefun Context.saveJsonToFile(fileName: String, json: String) { openFileOutput(fileName, Context.MODE_PRIVATE).use { stream -> stream.write(json.toByteArray()) } } fun Context.readJsonFromFile(fileName: String): String? { return try { openFileInput(fileName).bufferedReader().use { it.readText() } } catch (e: FileNotFoundException) { null } }

Handling nullable and default values

Kotlin — Safe defaults for missing fieldsdata class Article( val id: Int = 0, val title: String = "", val tags: List<String> = emptyList(), val author: Author? = null ) // Gson fills missing JSON fields with default values // Use nullable types (Author?) when the field may be absent or null

6Hands-On Exercises

1

Create a JSON object for a user with nested address. Write matching Kotlin data classes.

2

Build a JSON array of 5 posts. Parse it manually using JSONArray and display titles in a list.

3

Implement a JsonParser utility with try/catch for safe JSON parsing from assets.

4

Add Gson and replace manual parsing. Use @SerializedName for a snake_case API field.

5

Deserialize a JSONPlaceholder API response into List<Post> using Gson TypeToken.

6

Serialize a user object to JSON and save it in SharedPreferences. Load it back on app restart.

7

Bonus: Use Gson with Retrofit to fetch and display posts — compare the JSON string to your Kotlin objects in Logcat.

JSON Parsing MCQ Practice

10 Basic MCQs 10 Advanced MCQs

10 Basic JSON Parsing MCQs

1

JSON objects use?

ASquare brackets only
BCurly braces { key: value }
CAngle brackets
DSQL tables
Explanation: Objects hold key-value pairs.
2

JSON arrays use?

AParentheses
BCurly braces only
CSquare brackets [ item1, item2 ]
DSemicolons
Explanation: Arrays are ordered lists of values.
3

Gson converts JSON to?

ADrawables
BAPK files
CLayouts
DKotlin/Java objects (deserialization)
Explanation: Gson maps JSON fields to class properties.
4

JSONObject in Android?

Aorg.json API for manual parsing
BRoom entity
CService class
DManifest tag
Explanation: Built-in JSONObject.getString(), getInt(), etc.
5

Serialization means?

AJSON to object
BObject to JSON string
CEncrypt APK
DCompile Kotlin
Explanation: Serialize: object → JSON. Deserialize: JSON → object.
6

JSON string values use?

ANo quotes
BSingle quotes only
CDouble quotes
DBackticks
Explanation: JSON spec requires double-quoted strings.
7

JSONArray.getJSONObject(i)?

AConverts to XML
BDeletes array
CSorts array
DGets object at index i in array
Explanation: Iterate array length and get each JSONObject.
8

Gson fromJson needs?

AJSON string and Class/Type
BOnly XML
CManifest
DPermission
Explanation: gson.fromJson(json, User::class.java) for single object.
9

Nested JSON parsed by?

ASQL JOIN only
BNested JSONObject/getJSONObject or Gson nested classes
CIntent
DToast
Explanation: Model classes mirror nested structure or manual drill-down.
10

null in JSON means?

AEmpty string always
BZero
CValue is absent/null
DError
Explanation: Handle nullable types in Kotlin with ? or default values.

10 Advanced JSON Parsing MCQs

11

@SerializedName in Gson?

AEncrypts field
BMaps JSON key name to different field name
CRemoves field
DSQL column
Explanation: @SerializedName("user_name") val userName for snake_case APIs.
12

List deserialization Gson?

ARoom @Query
BArrayAdapter
CTypeToken for generic List<User>
DParcelable
Explanation: gson.fromJson(json, object : TypeToken>(){}.type)
13

kotlinx.serialization vs Gson?

ADeprecated
BIdentical
CGson only option
DKotlin-native compile-time serializer
Explanation: kotlinx.serialization with @Serializable is modern Kotlin alternative.
14

optString vs getString JSONObject?

AoptString returns fallback if missing; getString throws
BSame
CoptString throws
DgetString returns null
Explanation: opt methods safer for optional keys.
15

JsonReader streaming?

AImpossible
BParse large JSON without loading entire tree
CSlower always
DXML only
Explanation: Streaming reduces memory for huge payloads.
16

Moshi vs Gson?

AMoshi is XML
BNo difference
CMoshi Kotlin-friendly with codegen adapters
DGson required by Android
Explanation: Retrofit often uses Moshi or Gson converter.
17

Polymorphic JSON types?

ARoom only
BAutomatic always
CImpossible
DCustom TypeAdapter or sealed classes
Explanation: RuntimeAdapterFactory or discriminator field for subtypes.
18

Invalid JSON symptom?

AJsonSyntaxException or JSONException
BANR always
CLayout crash
DPermission denied
Explanation: Validate JSON; wrap parse in try/catch.
19

Pretty print JSON?

ALogcat only
BGsonBuilder().setPrettyPrinting().create()
CProGuard
DManifest
Explanation: Useful for debug logging formatted output.
20

Exclude field from Gson?

A@Composable
B@Entity
Ctransient keyword or @Expose
D@Path
Explanation: transient fields skipped by default in Gson.
Click an option to select, then check answers.

JSON Parsing Interview Q&A

15 topic-focused questions for interviews and revision.

1Parse simple JSON object manually.easy
Answer: JSONObject(json).getString("name"); getInt("age"); optString for optional fields.
2Convert Kotlin data class to JSON with Gson.easy
Answer: Gson().toJson(userObject) returns JSON string.
3Parse JSON array of users.easy
Answer: JSONArray loop or gson.fromJson with TypeToken List.
4Handle missing JSON keys.medium
Answer: Use optString with default, nullable properties, or Gson defaults.
5Snake_case API to camelCase Kotlin.medium
Answer: @SerializedName annotation or FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES.
6Difference serialization vs deserialization.easy
Answer: Serialization: object to JSON. Deserialization: JSON to object.
7When use org.json vs Gson.medium
Answer: org.json: small manual parses. Gson: automatic mapping to data classes.
8Nested JSON model design.medium
Answer: Create nested data classes matching structure; Gson maps recursively.
9Parse JSON from Retrofit.easy
Answer: Define response type; GsonConverterFactory deserializes body automatically.
10Common Gson pitfalls.hard
Answer: Field name mismatch, generic types need TypeToken, date format needs TypeAdapter.
11Validate JSON before parse.medium
Answer: Check null/empty response; isSuccessful; try/catch JsonSyntaxException.
12kotlinx.serialization setup brief.medium
Answer: Plugin @Serializable on data class; Json.decodeFromString(json).
13JSON vs XML on Android.easy
Answer: JSON dominant for REST APIs — lighter, easier with Gson/Moshi.
14Parse dynamic unknown keys.hard
Answer: JSONObject.keys() iteration or Map with Gson TypeToken.
15Security parsing JSON.medium
Answer: Don't eval JSON; validate schema; sanitize before displaying in WebView.