[英]Needed to filter null values from JSON response in spring boot project
公共 class APIService {
private List<CoinDTO> coinList = new ArrayList<>();
private final TrackerConfigProperties trackerConfig;
//Injecting configuration properties into the constructor.
public APIService(TrackerConfigProperties trackerConfig) {
this.trackerConfig = trackerConfig;
}
public List<CoinDTO> getCoinList() {
return coinList;
}
public void setCoinList(List<CoinDTO> coinList) {
this.coinList = coinList;
}
@PostConstruct
@Scheduled(cron = "* * 1 * * *")
public void getAPIData() throws IOException, JSONException{
List<CoinDTO> newData = new ArrayList<>();
OkHttpClient client = new OkHttpClient();
JSONObject obj = null;
JSONObject data = null;
//Use request builder to configure api
Request request = new Request.Builder()
.url(trackerConfig.apiUrl())
.get()
.addHeader("X-RapidAPI-Key", trackerConfig.apiKey())
.addHeader("X-RapidAPI-Host", trackerConfig.apiHost())
.build();
Response response = null;
try {
response = client.newCall(request).execute();
String jsonResponse = response.body().string();
System.out.println(jsonResponse);
obj = new JSONObject(jsonResponse);
data = obj.getJSONObject("data");
JSONArray arr = data.getJSONArray("coins");
System.out.println(arr);
for(int i=0; i<arr.length(); i++) {
CoinDTO coinRecords = new CoinDTO();
coinRecords.setName(arr.getJSONObject(i).getString("name"));
coinRecords.setSymbol(arr.getJSONObject(i).getString("symbol"));
coinRecords.setPrice(arr.getJSONObject(i).getFloat("price"));
coinRecords.setRank(arr.getJSONObject(i).getInt("rank"));
coinRecords.setChange(arr.getJSONObject(i).getFloat("change"));
coinRecords.setUrl(arr.getJSONObject(i).getString("iconUrl"));
coinRecords.setMarketCap(arr.getJSONObject(i).getString("marketCap"));
newData.add(coinRecords);
}
this.coinList = newData;
}catch(IOException e) {
e.printStackTrace();
}
// Requesting response.body().string() more than once will cause illegal state exception.
}
}
来自 crypto API 的 JSON 响应看起来很可疑。 1-60个结果,获取数据没有问题。 但是当我将响应计数增加到 100 个硬币时。 其中一些有 null 个值,这给了我数字格式异常。 如下所示,
Caused by: org.json.JSONException: JSONObject["change"] is not a number.
at org.json.JSONObject.getFloat(JSONObject.java:655) ~[json-20180130.jar:na]
at com.vish.trackerapp.service.APIService.getAPIData(APIService.java:86) ~[classes/:na]
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:na]
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77) ~[na:na]
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:na]
at java.base/java.lang.reflect.Method.invoke(Method.java:568) ~[na:na]
at org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor$LifecycleElement.invoke(InitDestroyAnnotationBeanPostProcessor.java:424) ~[spring-beans-6.0.2.jar:6.0.2]
at org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor$LifecycleMetadata.invokeInitMethods(InitDestroyAnnotationBeanPostProcessor.java:368) ~[spring-beans-6.0.2.jar:6.0.2]
at org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor.postProcessBeforeInitialization(InitDestroyAnnotationBeanPostProcessor.java:192) ~[spring-beans-6.0.2.jar:6.0.2]
... 37 common frames omitted
Caused by: java.lang.NumberFormatException: For input string: "null"
at java.base/jdk.internal.math.FloatingDecimal.readJavaFormatString(FloatingDecimal.java:2054) ~[na:na]
at java.base/jdk.internal.math.FloatingDecimal.parseFloat(FloatingDecimal.java:122) ~[na:na]
at java.base/java.lang.Float.parseFloat(Float.java:476) ~[na:na]
at org.json.JSONObject.getFloat(JSONObject.java:653) ~[json-20180130.jar:na]
... 45 common frames omitted
Json回复如下,
{
"uuid": "aQx_vW8s1",
"symbol": "XEC",
"name": "eCash",
"color": null,
"iconUrl": "https://cdn.coinranking.com/wdqRaUEhn/xec.png",
"marketCap": "458134192",
"price": "0.000023888579923343",
"listedAt": 1634887994,
"tier": 1,
"change": "0.07",
"rank": 73,
"sparkline": [
"0.000023888455899517",
"0.000023873825475088",
"0.00002383507280166",
"0.000023738913764452",
"0.000023705304867018",
"0.000023643911925818",
"0.000023626155269768",
"0.000023699523887097",
"0.000023745220955252",
"0.000023820571142281",
"0.000023801617704237",
"0.000023816460854558",
"0.000023795169626986",
"0.000023858079419847",
"0.000023892553157129",
"0.000023849240281632",
"0.000023857584839752",
"0.000024048737766589",
"0.00002392004515143",
"0.000023808725016789",
"0.000023751508927767",
"0.000023764344487179",
"0.000023826878245569",
"0.000023885406955056",
"0.000023888537567965"
],
"lowVolume": false,
"coinrankingUrl": "https://coinranking.com/coin/aQx_vW8s1+ecash-xec",
"24hVolume": "5918517",
"btcPrice": "1.416302521e-9"
}
我试过这个想法,但无法弄清楚如何将其包含在我的代码中。
newData.stream().filter(v -> v != null);
非常感谢任何建议或想法。
在我看来,一个好的解决方案是使用映射器和 DTO 来处理 json,因为在那里您可以使用 @JsonProperty 标记,使 json 字段不是强制性的。
以下是如何使用映射器:
ObjectMapper om = new ObjectMapper();
om.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);
JSONObject battle= new JSONObject(text);
JSONObject battleObject = battle.getJSONObject(JsonObject);
try{
Battle battleDto = om.readValue(battleObject.toString(), Battle.class);
return battleDto;
}catch (JsonProcessingException e ){
throw new NoStarPlayerException("No starPlayer for this battle ="+battle.toString());
}
这里是 DTO:
public class Battle {
@JsonProperty("battleTime")
String battletime;
@JsonIgnore()
String map;
@JsonProperty("mode")
String mode;
@JsonProperty("type")
String type;
@JsonProperty("result")
String result;
@JsonProperty("duration")
int duration;
@JsonProperty("trophyChange")
int trophyChange;
@JsonProperty("starPlayer")
StarPlayer starPlayer;
@JsonProperty("teams")
ArrayList<ArrayList<Player>> teams;
@JsonProperty("players")
ArrayList<Player>players;
@JsonProperty("rank")
int rank;
要解决缺少的 Json 字段,您可以使用 @JsonIgnore(如果您对该字段不感兴趣)或 @JsonProperty(value = "battleTime",required = false) 如果它可能是也可能不是 null。
我希望我能帮助你,问候
您使用的 json.org 库是 JSON 的一个很好的培训工具,但在实际使用中不是很好。 可用的最佳库是JSON-Jackson和Gson (来自 Google)。 我个人更喜欢 JSON-Jackson。 使用其中之一来解析您的 JSON ,您将轻松解决问题。
此外,对于像这样的简单情况,我在 JSON-Jackson 库上编写了自己的瘦包装器,它允许您序列化和解析 JSON 到/从 java class。这是JsonUtils class 的 Javadoc 。 您的代码可能如下所示:
HashMap<String, Object> map;
try {
map = JsonUtils.readObjectFromJsonString(jsonStr, Map.class);
} catch (IOException e) {
...
}
您可以编写自己的 DTO class 而不是 Map,而不是将Map.class
替换为您自己的 class 实例。 JsonUtils class 附带由我编写和维护的开源 MgntUtils 库。 该图书馆可以从 Maven Central here或Github 获得
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.