How to parse JSON with Retrofit Converters using Kotlin

UPDATE [February 9th, 2021]: Kotlin Android Extensions replaced with View Binding. If you don’t know anything about View Binding, read here.

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.7.0' // ... }
Code language: Kotlin (kotlin)

And in the top-level build.gradle file add the classpath:

buildscript { // ... dependencies { // ... classpath "org.jetbrains.kotlin:kotlin-serialization:1.4.10" } }
Code language: Swift (swift)

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
4 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
Emre

Best tutorial about retrofit!

Emre

Kotlin extensions was depreciated. Will you update it?

Emre

Thanks!