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
Contents
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 questions, please feel free to leave a comment below