Написать класс для работы с Retrofit
У меня есть ответ в виде json
{
"Date": "2020-09-19T11:30:00+03:00",
"PreviousDate": "2020-09-18T11:30:00+03:00",
"PreviousURL": "\/\/www.cbr-xml-daily.ru\/archive\/2020\/09\/18\/daily_json.js",
"Timestamp": "2020-09-18T17:00:00+03:00",
"Valute": {
"AUD": {
"ID": "R01010",
"NumCode": "036",
"CharCode": "AUD",
"Nominal": 1,
"Name": "Австралийский доллар",
"Value": 54.9008,
"Previous": 54.8842
},
"AZN": {
"ID": "R01020A",
"NumCode": "944",
"CharCode": "AZN",
"Nominal": 1,
"Name": "Азербайджанский манат",
"Value": 44.1624,
"Previous": 44.2579
},
.....<очень много различной валюты>....
"JPY": {
"ID": "R01820",
"NumCode": "392",
"CharCode": "JPY",
"Nominal": 100,
"Name": "Японских иен",
"Value": 71.7459,
"Previous": 71.7672
}
}}
Я работал с retrofit до этого, но не понимаю, как сделать так, чтобы не создавать для каждого вида валюты свой класс.
Сейчас моя структура выглядит так:
class Course{
val Date: String? = null
val PreviousDate : String? = null
val PreviousURL : String? = null
val Timestamp: String? = null
val Valute: List<Money?>?=null
}
data class Money (
val ID:String,
val NumCode:String,
val CharCode:String,
val Nominal: String,
val Name:String,
val Value:Double,
val Previous:Double
)
У меня появляется ошибка
Expected BEGIN_ARRAY but was BEGIN_OBJECT at line 6 column 16 path $.Valute
скорее всего ошибка в том, как я представляю Valute. Но что именно неправильно, я не понимаю.
Воспользовался сейчас онлайн конвертером в POJO ,это помогло прояснить ситуацию. Вопрос только в том, можно ли не создавать отдельный класс для каждой валюты (типа класс AZN и AUD отличаются только названиями, все поля у них одинаковые)?
Ответы (1 шт):
Возьмем структуру наподобие Вашей, но с мЕньшим числом полей (для краткости примера).
"Valute": {
"AUD": {
"ID": "R01010"
},
"AZN": {
"ID": "R01020A"
},
.....<очень много различной валюты>....
"JPY": {
"ID": "R01820"
}
}
Создадим data class для хранения этой структуры:
data class Valute (
val valutes: Map<String, ValuteInfo>
)
data class ValuteInfo (
val ID : String
)
Создадим кастомный десериализатор:
class ValuteDeserializer : JsonDeserializer<Valute> {
private val defaultGson = Gson()
override fun deserialize(
json: JsonElement?,
typeOfT: Type?,
context: JsonDeserializationContext?
): Valute? {
val obj = json?.asJsonObject
val entry = obj?.entrySet()?.iterator()?.next() ?: return null
val values = mutableMapOf<String, ValuteInfo>()
entry.value.asJsonObject.entrySet().forEach {
values[it.key] = defaultGson.fromJson(it.value, ValuteInfo::class.java)
}
return Valute(values)
}
}
И создаем Gson через билдер:
val gson = GsonBuilder()
.registerTypeAdapter(Valute::class.java, ValuteDeserializer())
.create()
Пример использования:
val jsonString = "{\"Valute\": {\n" +
" \"AUD\": {\n" +
" \"ID\": \"R01010\"\n" +
" },\n" +
" \"AZN\": {\n" +
" \"ID\": \"R01020A\"\n" +
" },\n" +
" \"JPY\": {\n" +
" \"ID\": \"R01820\"\n" +
" }\n" +
" }}"
val gson = GsonBuilder()
.registerTypeAdapter(Valute::class.java, ValuteDeserializer())
.create()
val valute = gson.fromJson(jsonString, Valute::class.java)
println(valute)