Java 缺少ArrayList方括号的JSONObject

Java 缺少ArrayList方括号的JSONObject,java,json,arraylist,Java,Json,Arraylist,我正在尝试从https://api.ratesapi.io/api/latest到自定义货币类的数组列表中: 公共类货币{ 私有字符串短名称; 私人双费率; ... } JSON看起来像: {"base":"EUR","rates":{"GBP":0.90033,"HKD":9.1786,"IDR":17304.0, "ILS":4.0309,"

我正在尝试从
https://api.ratesapi.io/api/latest
到自定义
货币类的
数组列表中

公共类货币{
私有字符串短名称;
私人双费率;
...
}
JSON看起来像:

{"base":"EUR","rates":{"GBP":0.90033,"HKD":9.1786,"IDR":17304.0,
 "ILS":4.0309,"DKK":7.45,"INR":88.765,"CHF":1.0759,"MXN":26.615,
 "CZK":26.202,"SGD":1.6236,"THB":36.832,"HRK":7.468,"MYR":4.9604,
 "NOK":10.6538,"CNY":8.2325,"BGN":1.9558,"PHP":58.136,"SEK":10.3165,
 "PLN":4.4073,"ZAR":20.7655,"CAD":1.5748,"ISK":160.2,"BRL":6.334,
 "RON":4.836,"NZD":1.7828,"TRY":8.5853,"JPY":124.96,"RUB":86.9321,
 "KRW":1404.99,"USD":1.1843,"HUF":346.23,"AUD":1.6492},"date":"2020-08-06"}
使用
org.json
我设法将数据放入
JSONObject

JSONObject obj=新的JSONObject(getJSON(“https://api.ratesapi.io/api/latest"));
据我所知,现在的正常过程是将
JSONObject
转换为
JSONArray
。不管怎样:

JSONArray JSONArray=obj.getJSONArray(“费率”);
失败,并显示错误消息:

线程“main”org.json.JSONException中的异常:JSONObject[“rates”]
不是JSONArray。
我该如何修复这个错误,或者是否有其他方法可以使用JSON生成ArrayList

我怀疑问题在于JSON字符串中缺少方括号。

您可以使用类将
JSON
从一些
URL
转换为某种对象。在这种情况下(如果
json
结构始终相同),它可以是
Map

ObjectMapper mapper=new ObjectMapper();
URL=新URL(“https://api.ratesapi.io/api/latest");
Map Map=mapper.readValue(url,Map.class);
系统输出打印项次(map);
//{基数=欧元,利率=英镑=0.90373,港币=9.1585,…,澳元=1.6403},日期=2020-08-07}
然后,您可以获取内部
速率
映射,并(如果需要)使用
java流api将其转换为列表:

Map rates=(Map)Map.get(“rates”);
系统输出打印项次(费率);//{英镑=0.90373,港币=9.1585,…,澳元=1.6403}
Map
转换为
ArrayList

ArrayList list=rates.entrySet().stream()
.map(条目->新货币(entry.getKey(),entry.getValue())
.collect(ArrayList::new,ArrayList::add,ArrayList::addAll);
System.out.println(列表);//[英镑=0.90373,港币=9.1585,…,澳元=1.6403]
注意:添加一个包含两个字段的构造函数
shortName
rate

注意:重写
toString
方法如下:
shortName+“=”+rate


Maven依赖项:


com.fasterxml.jackson.dataformat
.

对象“
rates
”不是JSONArray,而是JSONObject


因此,您必须执行
obj.getJSONObject(rates”);
然后使用map方法(例如使用keySet())在JSONObject的字段上迭代如果查看API返回的JSON,您会得到一个JSON对象:

{"base":"EUR","rates":{"GBP":0.90033,"HKD":9.1786, ... },"date":"2020-08-06"}
您可能希望执行以下操作:

JSONObject obj = new JSONObject(getJSON("https://api.ratesapi.io/api/latest"));
JSONObject rates = obj.getJSONObject("rates");
final Iterator<String> keys = rates.keys();
while (keys.hasNext()) {
  final String key = keys.next();
  final Currency currency = new Currency(key, rates.getDouble(key));
  // do something with the Currency
}
JSONObject obj=新的JSONObject(getJSON(“https://api.ratesapi.io/api/latest"));
JSONObject rates=obj.getJSONObject(“rates”);
最终迭代器键=rates.keys();
while(keys.hasNext()){
最后一个字符串键=keys.next();
最终货币=新货币(键,rates.getDouble(键));
//用货币做点什么
}

使用Jackson library和Lombok的工作解决方案可能如下所示:

import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import lombok.*;
import java.util.*;
import java.util.stream.Collectors;

public class CcyApiParser {
    @Getter
    @Setter
    @AllArgsConstructor
    @NoArgsConstructor
    @ToString
    public static class Currency {
        private String shortName;
        private double rate;
    }

    @Getter
    @Setter
    public static class RatesApiResponse {
        private String base;
        private Map<String, Double> rates;
        @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd")
        private LocalDate date;
    }


    public static void main(String[] args) throws IOException {

        ObjectMapper mapper = new ObjectMapper()
                .registerModule(new JavaTimeModule()); // to parse date

        URL apiUrl = new URL("https://api.ratesapi.io/api/latest");
    
        // read proper api response
        RatesApiResponse rates = mapper.readValue(apiUrl, RatesApiResponse.class);

        // convert inner rates into list of Currency objects
        List<Currency> ccys = rates.getRates().entrySet().stream()
                .map(e -> new Currency(e.getKey(), e.getValue()))
                .collect(Collectors.toList());

        ccys.forEach(ccy -> System.out.printf("%s=%s%n", ccy.getShortName(), ccy.getRate()));
    }
}
更新

还可以自定义RatesAPI响应的反序列化,并将
“rates”
的映射移动到此类中,以立即转换为货币列表

    @Getter
    @Setter
    public static class RatesApiResponse {
        private String base;
        @JsonProperty(access = JsonProperty.Access.READ_ONLY)
        private List<Currency> ccys;

        @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd")
        private LocalDate date;

        // no getter for rates
        // this customized setter for the map of rates converts into a list
        @JsonProperty("rates")
        public void setRates(Map<String, Double> rates) {
            ccys = rates.entrySet().stream()
                    .map(e -> new Currency(e.getKey(), e.getValue()))
                    .collect(Collectors.toList());
        }
    }

// Updates in the test method
RatesApiResponse rates = mapper.readValue(src, RatesApiResponse.class);

rates.getCcys().forEach(ccy -> System.out.printf("%s=%s%n", ccy.getShortName(), ccy.getRate()));
@Getter
@塞特
公共静态类费率响应{
私有字符串基;
@JsonProperty(access=JsonProperty.access.READ_ONLY)
私人名单CCY;
@JsonFormat(shape=JsonFormat.shape.STRING,pattern=“yyyy-MM-dd”)
私有本地日期;
//没有价格的吸气剂
//这个自定义的速率映射设置器将转换为一个列表
@JsonProperty(“费率”)
公共无效设置率(映射率){
ccys=rates.entrySet().stream()
.map(e->新货币(e.getKey(),e.getValue())
.collect(Collectors.toList());
}
}
//测试方法的更新
RatesApiResponse rates=mapper.readValue(src,RatesApiResponse.class);
rates.getCcys().forEach(ccy->System.out.printf(“%s=%s%n”,ccy.getShortName(),ccy.getRate());
线程“main”org.json.JSONException中的异常:JSONObject[“rates”] 不是JSONArray

出现此错误是因为
rates
不是数组形式。它只是一个类似
base
date
的元素,但看起来像数组。从JSON字符串中获取它,就像从中获取
base
date
一样,然后处理它以创建所需的
列表

下面给出了工作代码,并在代码中添加了注释:

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.net.URL;
import java.net.URLConnection;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.List;

import org.json.JSONException;
import org.json.JSONObject;

class Currency {
    private String shortName;
    private double rate;

    public Currency(String shortName, double rate) {
        this.shortName = shortName;
        this.rate = rate;
    }

    @Override
    public String toString() {
        return shortName + ":" + rate;
    }
}

public class Main {

    public static JSONObject getJSON(String url) throws IOException, JSONException {
        // Create a URLConnection for the given URL
        URLConnection connection = new URL(url).openConnection();

        // Add header to avoid 403 Forbidden HTTP status code
        connection.addRequestProperty("User-Agent",
                "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.14; rv:79.0) Gecko/20100101 Firefox/79.0" + "");

        StringBuilder jsonStr = new StringBuilder();

        // Get InputStream from connection and read the response
        try (InputStream is = connection.getInputStream();) {
            Reader reader = new BufferedReader(new InputStreamReader(is, Charset.forName("UTF-8")));

            int ch;
            while ((ch = reader.read()) != -1) {
                jsonStr.append((char) ch);
            }
        }
        return new JSONObject(jsonStr.toString());
    }

    public static void main(String[] args) throws IOException, JSONException {
        JSONObject jsonObj = getJSON("https://api.ratesapi.io/api/latest");

        // Get rates from jsonObj
        String rates = jsonObj.get("rates").toString();

        // Remove {, }, and " from the string
        String[] keyValArr = rates.replaceAll("[\\{\\\"}]", "").split(",");

        // List object to hold Currency objects
        List<Currency> list = new ArrayList<>();

        for (String keyVal : keyValArr) {
            // Split each key:value string on ':'
            String[] curRate = keyVal.split(":");

            // Add Currency object to List
            list.add(new Currency(curRate[0], Double.parseDouble(curRate[1])));
        }

        // Display list
        list.forEach(System.out::println);
    }
}

这是否回答了您的问题?@kaustubhkhhare虽然相关,但dupe不会帮助OP,因为他们要解析的类与JSON内容的结构不匹配。更接近的问题是,
rates
是一个属性与
Currency
结构匹配的对象,您需要转换e> 将
对象划分为其属性数组。注意:我使用了Firefox插件,以便在处理货币数据时获得标题的值,
User Agent
@user1583209。我建议不要使用double进行计算。而是使用
bigdecim
来避免舍入问题。类似于
new bigdecimemal(rates.getString(key))
可能就可以了
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.net.URL;
import java.net.URLConnection;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.List;

import org.json.JSONException;
import org.json.JSONObject;

class Currency {
    private String shortName;
    private double rate;

    public Currency(String shortName, double rate) {
        this.shortName = shortName;
        this.rate = rate;
    }

    @Override
    public String toString() {
        return shortName + ":" + rate;
    }
}

public class Main {

    public static JSONObject getJSON(String url) throws IOException, JSONException {
        // Create a URLConnection for the given URL
        URLConnection connection = new URL(url).openConnection();

        // Add header to avoid 403 Forbidden HTTP status code
        connection.addRequestProperty("User-Agent",
                "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.14; rv:79.0) Gecko/20100101 Firefox/79.0" + "");

        StringBuilder jsonStr = new StringBuilder();

        // Get InputStream from connection and read the response
        try (InputStream is = connection.getInputStream();) {
            Reader reader = new BufferedReader(new InputStreamReader(is, Charset.forName("UTF-8")));

            int ch;
            while ((ch = reader.read()) != -1) {
                jsonStr.append((char) ch);
            }
        }
        return new JSONObject(jsonStr.toString());
    }

    public static void main(String[] args) throws IOException, JSONException {
        JSONObject jsonObj = getJSON("https://api.ratesapi.io/api/latest");

        // Get rates from jsonObj
        String rates = jsonObj.get("rates").toString();

        // Remove {, }, and " from the string
        String[] keyValArr = rates.replaceAll("[\\{\\\"}]", "").split(",");

        // List object to hold Currency objects
        List<Currency> list = new ArrayList<>();

        for (String keyVal : keyValArr) {
            // Split each key:value string on ':'
            String[] curRate = keyVal.split(":");

            // Add Currency object to List
            list.add(new Currency(curRate[0], Double.parseDouble(curRate[1])));
        }

        // Display list
        list.forEach(System.out::println);
    }
}
CHF:1.0804
HRK:7.4595
MXN:26.5127
...
...
...
NZD:1.7786
BRL:6.3274