Retrofit 2, GSON and Data Classes with Kotlin

Thomas Cundell
3 min readSep 25, 2018

--

Getting around an array with multiple custom Data Classes from your API.

The Problem

When rewriting my company’s app I encountered an issue, which at first I thought would be a pain to resolve. The issue was I had a response from our API that gave me an array of objects, both of which had different yet similar properties. Then I realised it’s actually quite easy and nice thanks to Kotlin.

Using retrofit2 and Gson for other responses I was simply using code like this to generate a List property in a data class:

val customDataClassList: List<CustomDataClass>

However, I felt this could no longer be done due to having two different data objects as part of a List. My initial thought was that the only solution would be to implement a new interceptor in my retrofit service, but, I found an alternative.

The two custom data classes were very similar. The payload looked like this:

Example of API Response

So as you can see we have an arrayList(data) with two different objects which have similarities. Originally I tried this:

response.kt

data class response(@SerializedName(refresh_time) val refreshTime: Long,
val data: List<Any>)

tableData.kt

data class tableData(val type: String,
val table: List<TableObjects>)

legendData.kt

data class legendData(val type: String,
val legend: List<LegendObjects>)

This was in the hope that using ‘Any’ the app would be able to infer at run time that we were looking for tableData or legendData. However this was not the case. Instead GSON creates a LinkedTreeMap for the objects. Which is still helpful and from that you could create all the objects manually in code with a bunch of for loops, but that would be expensive. Instead what we can do is create a parent data class with nullable objects.

This means our data classes now look like this:

response.kt

data class response(@SerializedName(refresh_time) val refreshTime: Long,
val data: List<ParentData>)

parentData.kt

data class parentData(val type: String,
var table: List? = null,
var legend: List? = null)

So now when GSON converts the response from the API we have a list of parent data, where when it is of type “table” the table property is populated with our custom data class and likewise when we have type “legend”. You will notice response.kt is the solution I first thought I couldn’t use at the top of this article.

This is not an ideal solution, the better solution would be to change the response from the API but you may not have the capacity to do that. And I’m sure there are other way rounds it this to me felt like the easiest and most practical way.

Originally published at thomas.cundell.com on September 25, 2018.

--

--

Thomas Cundell

Android Engineer for Weezy. Sports Analyst hobbyist and Host of The Backroom Staff Podcast Twitter: @BKRMStaff and @THCundell