Got retrofit response like this from currency Api:
Using the "data class from json" plugin will create a data class for "result" with currencies as parametеr:
I can add all currencies(more than 170+) to this class as params. But if the list of currencies will change, I needed to change classes too.
Maybe we can somehow convert "results" from object "Result" to Map<String, String> ?
List of currencies can be massive:
retrofit creation:
@Provides
@Singleton
fun provideRemoteClient(): Retrofit {
return Retrofit.Builder()
.baseUrl(BASE_URL)
.addConverterFactory(ScalarsConverterFactory.create())
.addConverterFactory(GsonConverterFactory.create())
.client(provideHttpClient())
.build()
}
httpClient:
@Provides
@Singleton
fun provideHttpClient(): OkHttpClient {
val loggingInterceptor = HttpLoggingInterceptor().apply {
level = HttpLoggingInterceptor.Level.BODY
}
val queryInterceptor = Interceptor { chain ->
val original: Request = chain.request()
val originalHttpUrl: HttpUrl = original.url
val url = originalHttpUrl.newBuilder()
.addQueryParameter("api_key", Constants.API_KEY)
.build()
val requestBuilder: Request.Builder = original.newBuilder()
.url(url)
val request: Request = requestBuilder.build()
chain.proceed(request)
}
return OkHttpClient.Builder()
.addInterceptor(loggingInterceptor)
.addInterceptor(queryInterceptor)
.connectTimeout(10, TimeUnit.SECONDS)
.writeTimeout(10, TimeUnit.SECONDS)
.readTimeout(10, TimeUnit.SECONDS)
.build()
}
correct answer is here: How to convert similar Json objects to Json Arrays with Gson and Retrofit
We need to create custom json-deserializer class and parse object as entrySet.
for my example this class will be like this:
class FetchResultDeserializer : JsonDeserializer<FetchApiResponse> {
override fun deserialize(json: JsonElement?, typeOfT: Type?, context: JsonDeserializationContext?): FetchApiResponse {
if (json == null || context == null) {
throw Exception("deserialize Error")
}
val obj = json.asJsonObject
val base = context.deserialize<String?>(obj.get("base"), String::class.java)
val resultSet = obj.get("results").asJsonObject.entrySet()
val resultList = resultSet.map {
val code = it.key
val value = it.value.asString
Currency(code, value)
}
val updated = context.deserialize<String?>(obj.get("updated"), String::class.java)
val ms = context.deserialize<Int?>(obj.get("ms"), Int::class.java)
return FetchApiResponse(base = base, ms = ms, results = resultList, updated = updated)
}}
data class FetchApiResponse(
val base: String? = null,
val ms: Int? = null,
val results: List<Currency> ? = null,
val updated: String ? = null)
data class Currency(val name:String, val value: String)
as result we got list, not a object: