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