Как получить ArrayList из JSONObject?

Пытаюсь получить массив данных из json по ссылке: https://api.ratesapi.io/api/latest и преобразовать его в ArrayList<Currency>. Класс Currency выглядит так:

public class Currency {
    private String name;
    private double rate;
}

Полученный json выглядит так:

{"base":"EUR","rates":{"GBP":0.90155,"HKD":9.1166,"IDR":17221.03,
"ILS":4.0124,"DKK":7.4479,"INR":88.1125,"CHF":1.079,"MXN":26.3047,
"CZK":26.183,"SGD":1.6158,"THB":36.63,"HRK":7.4828,"MYR":4.9352,
"NOK":10.629,"CNY":8.2003,"BGN":1.9558,"PHP":57.787,"SEK":10.2805,
"PLN":4.4021,"ZAR":20.8452,"CAD":1.5739,"ISK":160.6,"BRL":6.3697,
"RON":4.836,"NZD":1.784,"TRY":8.6055,"JPY":124.74,"RUB":86.6154,
"KRW":1396.28,"USD":1.1763,"HUF":345.19,"AUD":1.6445},"date":"2020-08-10"}

С помощью org.json записываю данные в JSONObject:

JSONObject object = new JSONObject(getJSON("https://api.ratesapi.io/api/latest"));

Затем пытаюсь преобразовать объект JSONObject в массив JSONArray:

JSONArray array = object.getJSONArray("rates");

Этот код выдает ошибку:

Exception in thread "main" org.json.JSONException: JSONObject["rates"]
is not a JSONArray.

Что я делаю не так? Каким образом получить ArrayList из строки json?


Есть подозрение, что проблема в отсутствии квадратных скобок в строке json.


Ответы (2 шт):

Автор решения: Дмитрий

Посмотрите внимательно на исходный JSON, все дело в том, что в нем не List, а Map, посему при попытке преобразовать это в лист вы получаете вполне справедливое исключение. Я думаю, что вы без труда разберете этот код и поймете в чем проблема:

List<Currency> result = object.getJSONObject("rates").toMap().entrySet().stream()
    .map(e -> new Currency(e.getKey(), Double.valueOf(e.getValue().toString())))
    .collect(Collectors.toList());

И сам класс Currency с конструктором:

class Currency {
    private String name;
    private double rate;

    public Currency(String name, double rate) {
        this.name = name;
        this.rate = rate;
    }
}
→ Ссылка
Автор решения: Podushkoved

Для получения json из URL и преобразования его в объект можно использовать ObjectMapper. В данном случае (если структура json всегда одинакова) это может быть Map<String, Object>.

ObjectMapper mapper = new ObjectMapper();
URL url = new URL("https://api.ratesapi.io/api/latest");
Map<String, Object> map = mapper.readValue(url, Map.class);

System.out.println(map);
// {base=EUR, rates={GBP=0.89843, HKD=9.132, ... , AUD=1.6406}, date=2020-08-11}

Получаем из этой карты внутреннюю карту rates:

Map<String, Double> rates = (Map<String, Double>) map.get("rates");

System.out.println(rates); // {GBP=0.89843, HKD=9.132, ... , AUD=1.6406}

Преобразовываем карту Map<String, Double> в ArrayList<Currency>:

ArrayList<Currency> list = rates.entrySet().stream()
    .map(entry -> new Currency(entry.getKey(), entry.getValue()))
    .collect(ArrayList::new, ArrayList::add, ArrayList::addAll);

System.out.println(list); // [GBP=0.89843, HKD=9.132, ... , AUD=1.6406]

Замечание: добавляем конструктор с двумя полями name и rate;
Замечание: переопределяем метод toString так: shortName + "=" + rate;


Зависимость Maven:

<dependency>
    <groupId>com.fasterxml.jackson.dataformat</groupId>
    <artifactId>jackson-dataformat-xml</artifactId>
    <version>2.11.2</version>
</dependency>
→ Ссылка