I'm trying the build an app where users can see a list of different plants around the globe. For this I am trying to use Retrofit2 and GSon to get my response from the Perenual Plant Doc API. This is what my response looks looks like:
{
"data": [
{
"id": 1,
"common_name": "European Silver Fir",
"scientific_name": [
"Abies alba"
],
"other_name": [
"Common Silver Fir"
],
"cycle": "Perennial",
"watering": "Frequent",
"sunlight": [
"full sun"
],
"default_image": {
"license": 45,
"license_name": "Attribution-ShareAlike 3.0 Unported (CC BY-SA 3.0)",
"license_url": "https://creativecommons.org/licenses/by-sa/3.0/deed.en",
"original_url": "https://perenual.com/storage/species_image/1_abies_alba/og/1536px-Abies_alba_SkalitC3A9.jpg",
"regular_url": "https://perenual.com/storage/species_image/1_abies_alba/regular/1536px-Abies_alba_SkalitC3A9.jpg",
"medium_url": "https://perenual.com/storage/species_image/1_abies_alba/medium/1536px-Abies_alba_SkalitC3A9.jpg",
"small_url": "https://perenual.com/storage/species_image/1_abies_alba/small/1536px-Abies_alba_SkalitC3A9.jpg",
"thumbnail": "https://perenual.com/storage/species_image/1_abies_alba/thumbnail/1536px-Abies_alba_SkalitC3A9.jpg"
}
},
{
"id": 2,
"common_name": "Pyramidalis Silver Fir",
"scientific_name": [
"Abies alba 'Pyramidalis'"
],
"other_name": [],
"cycle": "Perennial",
"watering": "Average",
"sunlight": [
"full sun"
],
"default_image": {
"license": 5,
"license_name": "Attribution-ShareAlike License",
"license_url": "https://creativecommons.org/licenses/by-sa/2.0/",
"original_url": "https://perenual.com/storage/species_image/2_abies_alba_pyramidalis/og/49255769768_df55596553_b.jpg",
"regular_url": "https://perenual.com/storage/species_image/2_abies_alba_pyramidalis/regular/49255769768_df55596553_b.jpg",
"medium_url": "https://perenual.com/storage/species_image/2_abies_alba_pyramidalis/medium/49255769768_df55596553_b.jpg",
"small_url": "https://perenual.com/storage/species_image/2_abies_alba_pyramidalis/small/49255769768_df55596553_b.jpg",
"thumbnail": "https://perenual.com/storage/species_image/2_abies_alba_pyramidalis/thumbnail/49255769768_df55596553_b.jpg"
}
}
],
"to": 30,
"per_page": 30,
"current_page": 1,
"from": 1,
"last_page": 337,
"total": 10102
}
Based on this response, there are two plants returned. When trying to get the data as if the response was just an array, I get this error: java.lang.IllegalStateException: Expected BEGIN_ARRAY but was BEGIN_OBJECT at line 1 column 2 path $
Here are my classes used for this entire ordeal: SpeciesListPlant.kt
data class SpeciesListPlant(
@SerializedName("common_name")
val commonName: String,
@SerializedName("cycle")
val cycle: String,
@SerializedName("default_image")
val defaultImage: DefaultImage,
@SerializedName("id")
val id: Int,
@SerializedName("other_name")
val otherName: List<String>,
@SerializedName("scientific_name")
val scientificName: List<String>,
@SerializedName("sunlight")
val sunlight: List<String>,
@SerializedName("watering")
val watering: String
)
SpeciesListInterface.kt
interface SpeciesListInterface {
@GET(ApiConstants.SPECIES_LIST_ENDPOINT_PERENUAL)
fun getSpeciesList(): Call<List<SpeciesListPlant>>
}
And this is how I get my data with retrofit
val retrofitBuilder = Retrofit.Builder()
.addConverterFactory(GsonConverterFactory.create())
.baseUrl(ApiConstants.BASE_URL_PERENUAL)
.build()
.create(SpeciesListInterface::class.java)
val retrofitData = retrofitBuilder.getSpeciesList()
retrofitData.enqueue(object : Callback<List<SpeciesListPlant>?> {
override fun onResponse(call: Call<List<SpeciesListPlant>?>, response: Response<List<SpeciesListPlant>?>) {
val responseBody = response.body()!!
Log.e("Retrofit data", responseBody.toString())
}
override fun onFailure(call: Call<List<SpeciesListPlant>?>, t: Throwable) {
t.printStackTrace()
}
})
I assume that I get this error because the data I want is nested within another object called "data" and not just nested within an array like [plant1, plant2]. How can I just get the array within this "data" field and will this solve this error?
Long story short, how can I get the array paired with the parent "data" field when I get the response.
The easiest solution would be to add a new enclosing data class which has this data
property:
data class SpeciesListResponse(
@SerializedName("data")
val data: List<SpeciesListPlant>
)
And then change the return type of your getSpeciesList()
function to use that data class instead:
fun getSpeciesList(): Call<SpeciesListResponse>