How to parse JSON with Retrofit Converters using Kotlin

Last updated on: September 9, 2021

In this tutorial, I will show you how to parse JSON using the following converters with Retrofit:

  • Gson converter
  • Moshi converter
  • Kotlinx Serialization converter
  • Jackson converter

I’m not going to explain how to set up Retrofit and make HTTP requests because I already did it in this tutorial, but only how to parse JSON with these converters.

I’m also going to cover 3 cases may you face when you’re trying to parse JSON:

  • Simple JSON: Just a simple JSON without any complex structure
  • Array JSON: The JSON structure begins with an array and without a key
  • Nested JSON: Includes nested objects

Adding the library

Go to your app-level build.gradle file, and add the converter

Gson Converter

dependencies {
    // (Coroutines, Retrofit)...

    // Gson Converter
    implementation 'com.squareup.retrofit2:converter-gson:2.9.0'

    // ...
}Code language: Kotlin (kotlin)

Moshi Converter

dependencies {
    // (Coroutines, Retrofit)...

    // Moshi Converter
    implementation 'com.squareup.retrofit2:converter-moshi:2.9.0'

    // ...
}Code language: Kotlin (kotlin)

Kotlinx Serialization Converter

apply plugin: 'kotlinx-serialization'

// ...

dependencies {
    // (Coroutines, Retrofit)...

    // Kotlinx Serialization Converter
    implementation 'com.jakewharton.retrofit:retrofit2-kotlinx-serialization-converter:0.8.0'

    // ...
}Code language: Kotlin (kotlin)

Jackson Converter

dependencies {
    // (Coroutines, Retrofit)...

    // Jackson Converter
    implementation 'com.squareup.retrofit2:converter-jackson:2.9.0'

    // ...
}Code language: Kotlin (kotlin)

Adding the Converter in Retrofit

In your Retrofit instance, you can add the converter by adding the line:
.addConverterFactory(THE_CONVERTER_YOU_PREFER)

val retrofit = Retrofit.Builder()
    .baseUrl("http://api.example.com/")
    .addConverterFactory(THE_CONVERTER_YOU_PREFER)
    .build()Code language: Kotlin (kotlin)

Gson Converter

.addConverterFactory(GsonConverterFactory.create())

Moshi Converter

.addConverterFactory(MoshiConverterFactory.create())

Kotlinx Serialization Converter:

.addConverterFactory(Json.asConverterFactory("application/json".toMediaType()))Code language: Swift (swift)

Jackson Converter

.addConverterFactory(JacksonConverterFactory.create())

Parsing simple JSON

A simple JSON doesn’t have any complex structure, like arrays, nested objects, e.t.c, and it looks like that:

{
    "id": "1",
    "employee_name": "Jack Full",
    "employee_salary": "300800",
    "employee_age": "61"
}Code language: Swift (swift)

Create a new data class file with the following fields:

// Uncomment the follow line if you're using the Kotlinx Serialization converter
// @Serializable
data class SimpleJSONModel(

    // Use @SerializedName(" ") for the Gson converter
    // @field:Json(name = " ") for the Moshi converter
    // @SerialName(" ") for the Kotlinx Serialization converter
    // @JsonProperty(" ") for the Jackson converter

    @SerializedName("id")
    var employeeId: String?,

    @SerializedName("employee_name")
    var employeeName: String?,

    @SerializedName("employee_salary")
    var employeeSalary: String?,

    @SerializedName("employee_age")
    var employeeAge: String?

)Code language: Kotlin (kotlin)

If the model’s variable names are different from the JSON field names (In this example, employeeId is different from the “id”), then use the converter’s annotation and indicate the field’s name in JSON.

In this example, we’re using the Gson converter, so the annotation for this is @SerializedName).

Next, in the APIService.kt file, add your model:

interface APIService {
    // ...

    @GET("/johncodeos-blog/ParseJSONRetrofitConvertersExample/main/simple.json")
    suspend fun getEmployee(): Response<SimpleJSONModel>

    // ...
}Code language: Kotlin (kotlin)

And lastly, your GET request:

fun parseJSON() {

    // Create Retrofit
    val retrofit = Retrofit.Builder()
        .baseUrl("https://raw.githubusercontent.com")
        .addConverterFactory(THE_CONVERTER_YOU_PREFER)
        .build()

    // Create Service
    val service = retrofit.create(APIService::class.java)
    CoroutineScope(Dispatchers.IO).launch {

        // Do the GET request and get response
        val response = service.getEmployees()

        withContext(Dispatchers.Main) {
            if (response.isSuccessful) {

                val items = response.body()
                if (items != null) {
                    for (i in 0 until items.count()) {
                        // ID
                        val id = items[i].employeeId ?: "N/A"
                        Log.d("ID: ", id)

                        // Employee Name
                        val employeeName = items[i].employeeName ?: "N/A"
                        Log.d("Employee Name: ", employeeName)

                        // Employee Salary
                        val employeeSalary = items[i].employeeSalary ?: "N/A"
                        Log.d("Employee Salary: ", employeeSalary)

                        // Employee Age
                        val employeeAge = items[i].employeeAge ?: "N/A"
                        Log.d("Employee Age: ", employeeAge)
                        
                    }
                }

            } else {

                Log.e("RETROFIT_ERROR", response.code().toString())

            }
        }
    }
}Code language: Kotlin (kotlin)

Parsing array JSON

JSON uses arrays to create a list of data. Some of them start with an array but without a key:

[
    {
        "id": "1",
        "employee_name": "Tiger Nixon",
        "employee_salary": "320800",
        "employee_age": "61"
    },
    {
        "id": "2",
        "employee_name": "Garrett Winters",
        "employee_salary": "170750",
        "employee_age": "63"
    },
    // ...
]Code language: Swift (swift)

Create a new data class file with the following fields (It’s the same with the simple JSON model):

// Uncomment the following line if you're using the Kotlinx Serialization converter
// @Serializable
data class ArrayJSONModel(

    // Use @SerializedName(" ") for the Gson converter
    // @field:Json(name = " ") for the Moshi converter
    // @SerialName(" ") for the Kotlinx Serialization converter
    // @JsonProperty(" ") for the Jackson converter

    @SerializedName("id")
    var employeeId: String?,

    @SerializedName("employee_name")
    var employeeName: String?,

    @SerializedName("employee_salary")
    var employeeSalary: String?,

    @SerializedName("employee_age")
    var employeeAge: String?

)Code language: Kotlin (kotlin)

Next, in the APIService.kt file, add a List with the model:

interface APIService {
    // ...

    @GET("/johncodeos-blog/ParseJSONRetrofitConvertersExample/main/array.json")
    suspend fun getEmployees(): Response<List<ArrayJSONModel>>

    // ...
}Code language: Kotlin (kotlin)

Then, your GET request:

fun parseJSON() {

    // Create Retrofit
    val retrofit = Retrofit.Builder()
        .baseUrl("https://raw.githubusercontent.com")
        .addConverterFactory(THE_CONVERTER_YOU_PREFER)
        .build()

    // Create Service
    val service = retrofit.create(APIService::class.java)
    CoroutineScope(Dispatchers.IO).launch {

        // Do the GET request and get response
        val response = service.getEmployees()

        withContext(Dispatchers.Main) {
            if (response.isSuccessful) {

                val items = response.body()
                if (items != null) {
                    for (i in 0 until items.count()) {
                        // ID
                        val id = items[i].employeeId ?: "N/A"
                        Log.d("ID: ", id)

                        // Employee Name
                        val employeeName = items[i].employeeName ?: "N/A"
                        Log.d("Employee Name: ", employeeName)

                        // Employee Salary
                        val employeeSalary = items[i].employeeSalary ?: "N/A"
                        Log.d("Employee Salary: ", employeeSalary)

                        // Employee Age
                        val employeeAge = items[i].employeeAge ?: "N/A"
                        Log.d("Employee Age: ", employeeAge)
                        
                    }
                }

            } else {

                Log.e("RETROFIT_ERROR", response.code().toString())

            }
        }
    }
}Code language: Kotlin (kotlin)

Parsing nested JSON

When a JSON object is inside another JSON object, it’s called ‘nested’ and will look like the following JSON structure:

{
    "data": [
        {
            "id": "1",
            "employee": {
                "name": "Tiger Nixon",
                "salary": {
                    "usd": 320800,
                    "eur": 273545
                },
                "age": "61"
            }
        },
        {
            "id": "2",
            "employee": {
                "name": "Garrett Winters",
                "salary": {
                    "usd": 170750,
                    "eur": 145598
                },
                "age": "63"
            }
        },
        // ...
    ]
}Code language: Swift (swift)

First, create a new data class file, and make a new data class for each nested object:

// Uncomment the following line if you're using the Kotlinx Serialization converter
// @Serializable
data class NestedJSONModel(

    // Use @SerializedName(" ") for the Gson converter
    // @field:Json(name = " ") for the Moshi converter
    // @SerialName(" ") for the Kotlinx Serialization converter
    // @JsonProperty(" ") for the Jackson converter

    var data: List<Data>?

)

// Uncomment the following line if you're using the Kotlinx Serialization converter
// @Serializable
data class Data(

    @SerializedName("id")
    val employeeId: String?,

    val employee: Employee?

)

// Uncomment the following line if you're using the Kotlinx Serialization converter
// @Serializable
data class Employee(

    val name: String?,

    val salary: Salary?,

    val age: String?

)

// Uncomment the following line if you're using the Kotlinx Serialization converter
// @Serializable
data class Salary(

    val eur: Int?,

    val usd: Int?

)Code language: Kotlin (kotlin)

Next, in the APIService.kt file, add the model as below:

interface APIService {
    // ...

    @GET("/johncodeos-blog/ParseJSONRetrofitConvertersExample/main/nested.json")
    suspend fun getEmployeesNested(): Response<NestedJSONModel>

    // ...
}Code language: Kotlin (kotlin)

And lastly, your GET request:

@SuppressLint("LongLogTag")
fun parseJSON() {
    // Create Retrofit
    val retrofit = Retrofit.Builder()
        .baseUrl("https://raw.githubusercontent.com")
        .addConverterFactory(THE_CONVERTER_YOU_PREFER)
        .build()

    // Create Service
    val service = retrofit.create(APIService::class.java)

    CoroutineScope(Dispatchers.IO).launch {

        // Do the GET request and get response
        val response = service.getEmployeesNested()

        withContext(Dispatchers.Main) {
            if (response.isSuccessful) {

                val items = response.body()?.data
                if (items != null) {
                    for (i in 0 until items.count()) {
                        // ID
                        val id = items[i].employeeId ?: "N/A"
                        Log.d("ID: ", id)

                        // Employee Name
                        val employeeName = items[i].employee?.name ?: "N/A"
                        Log.d("Employee Name: ", employeeName)

                        // Employee Salary in USD
                        val employeeSalaryUSD = items[i].employee?.salary?.usd ?: 0
                        Log.d("Employee Salary in USD: ", employeeSalaryUSD.toString())

                        // Employee Salary in EUR
                        val employeeSalaryEUR = items[i].employee?.salary?.eur ?: 0
                        Log.d("Employee Salary in EUR: ", employeeSalaryEUR.toString())

                        // Employee Age
                        val employeeAge = items[i].employee?.age ?: "N/A"
                        Log.d("Employee Age: ", employeeAge)
                        
                    }
                }

            } else {

                Log.e("RETROFIT_ERROR", response.code().toString())

            }
        }
    }
}Code language: Kotlin (kotlin)
You can find the final project here

If you have any questionsplease feel free to leave a comment below

Subscribe
Notify of
guest
13 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments