简体   繁体   English

Jackson JSON-从嵌套数组中提取数据

[英]Jackson JSON - Extract data from nested array


NOTE: I've rewritten this question ask it was too vauge beforehand, and I am unaware of how to approach this problem. 注意:我已经改写了这个问题,询问它是否事先过于庞大,并且我不知道如何解决此问题。


I'm currently trying to deserialize data from a RESTful API into POJO classes. 我目前正在尝试将来自RESTful API的数据反序列化为POJO类。 Each method of the API returns the same response structure, with the actual result having varying structures depending on the method. API的每种方法都返回相同的响应结构,实际结果根据方法的不同而变化。 I want to be able to map each method's result to its own POJO class. 我希望能够将每个方法的结果映射到其自己的POJO类。

Two of the sample JSON responses are of this structure, one returns an array of objects where the other returns a series of properties. 样本JSON响应中有两个具有这种结构,一个返回对象数组,另一个返回一系列属性。

In this case, each JSON object within 'result' should be deserialized into it's own POJO instance. 在这种情况下,应将“结果”中的每个JSON对象反序列化为它自己的POJO实例。

 { "success" : true, "message" : "", "result" : [{ "Frequency" : 0.25000 "Range" : 15.6 }, { "Frequency" : 0.12500 "Range" : 25.1 }, { "Frequency" : 0.00750 "Range" : 56.0 } ] } 

In this case, 'result' is the object and should map onto a single POJO instance. 在这种情况下,“结果”是对象,应映射到单个POJO实例。

 { "success" : true, "message" : "", "result" : { "Bid" : 2.05670368, "Ask" : 3.35579531, "Last" : 3.35579531 } } 

This will be a different class to previous example as it is a response from a different API method. 这是与先前示例不同的类,因为它是来自其他API方法的响应。 I am just wanting to extract the result, the success and message aren't required for any response. 我只想提取结果,任何响应都不需要成功和消息。

As your results response is dynamic I would suggest you not to include your results object in your deserialization. 由于results响应是动态的,因此建议您不要在反序列化中包括results对象。 Include the below code in your POJO class which does the deserailization. 在执行反序列化的POJO类中包括以下代码。

@JsonIgnore
private Map<String, Object> additionalProperties = new HashMap<String, Object>();

@JsonAnyGetter
public Map<String, Object> getAdditionalProperties() {
return this.additionalProperties;
}

@JsonAnySetter
public void setAdditionalProperty(String name, Object value) {
this.additionalProperties.put(name, value);
}

Now the Map with the name additionalProperties will contain the any additional objects that you hadn't tried to capture in the Parent object ( in this case it will have your results object). 现在Map名为additionalProperties将包含你还没有尝试过的父对象捕捉(在这种情况下,将有你的任何其他对象results对象)。 It stores either Object or list of Objects depending upon your response and you can access it with the key value results . 它根据您的响应存储ObjectObject list of Objects您可以使用键值results访问它。

As suggested by FlemingJp using a generic type seems like a much feasible solution for this question so I am including that part as well in this answer. 正如FlemingJp所建议的那样,对于该问题,使用泛型类型似乎是一个非常可行的解决方案,因此我也在此答案中也包括了这一部分。

public class Response<T> {

    private boolean success;
    private String message;
    private T result;

    public T getResult() {
        return result;
    }

    public String getMessage () {
       return message;
    }

    public boolean getSuccess() {
        return success;
    }
}

Example Usage 用法示例

ObjectMapper objectMapper = new ObjectMapper();

// When the result is one object
Response<DistanceStat> res = objectMapper.readValue(data, new TypeReference<Response<DistanceStat>>() {});

// For a collection of objects under result
Response<Collection<DistanceStat>> res = objectMapper.readValue(data, new TypeReference<Response<Collection<DistanceStat>>>() {});

Edit : 编辑

You can deserialize in jackson as follows: 您可以按照以下步骤在杰克逊中反序列化:

ObjectMapper mapper = new ObjectMapper();
String jsonInString //which contains your json data in string
ParentNode parentNode = mapper.readValue(jsonInString, ParentNode.class);

PraentNode being your parent class. PraentNode是您的父类。

Edit 2 : 编辑2

Note : This is very specific to your situation. Note :这非常适合您的情况。

These are the POJO classes you will be needing, the parent class to which you have to deserialize 这些是您将需要的POJO类,您必须反序列化的父类

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import com.fasterxml.jackson.annotation.JsonAnyGetter;
import com.fasterxml.jackson.annotation.JsonAnySetter;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonPropertyOrder;

@JsonInclude(JsonInclude.Include.NON_NULL)
@JsonPropertyOrder({
"success",
"message"
})
public class Example {

@JsonProperty("success")
private Boolean success;
@JsonProperty("message")
private String message;

@JsonIgnore
private Map<String, Object> additionalProperties = new HashMap<String, Object>();

@JsonProperty("success")
public Boolean getSuccess() {
return success;
}

@JsonProperty("success")
public void setSuccess(Boolean success) {
this.success = success;
}

@JsonProperty("message")
public String getMessage() {
return message;
}

@JsonProperty("message")
public void setMessage(String message) {
this.message = message;
}

@JsonAnyGetter
public Map<String, Object> getAdditionalProperties() {
return this.additionalProperties;
}

@JsonAnySetter
public void setAdditionalProperty(String name, Object value) {
this.additionalProperties.put(name, value);
}

}

I intentionally not included the Result class in here. 我故意不在此处包含Result类。 Now whatever the Result response you get will be stored in the Map named additional properties as an object which can be a list<Result> or class Result 现在,无论您获得什么Result响应,都将作为additional properties object存储在Map名为additional propertiesobject ,该object可以是list<Result>Result

Now you have two structures for Result object. 现在,您有两个用于Result对象的结构。 You can store them in same POJO. 您可以将它们存储在同一POJO中。 so let's construct two different POJO classes for each structure. 因此,让我们为每个结构构造两个不同的POJO类。

Result1.java Result1.java

import java.util.HashMap;
import java.util.Map;
import com.fasterxml.jackson.annotation.JsonAnyGetter;
import com.fasterxml.jackson.annotation.JsonAnySetter;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonPropertyOrder;

@JsonInclude(JsonInclude.Include.NON_NULL)
@JsonPropertyOrder({
"Frequency",
"Range"
})
public class Result1 {

@JsonProperty("Frequency")
private Double frequency;
@JsonProperty("Range")
private Double range;
@JsonIgnore
private Map<String, Object> additionalProperties = new HashMap<String, Object>();

@JsonProperty("Frequency")
public Double getFrequency() {
return frequency;
}

@JsonProperty("Frequency")
public void setFrequency(Double frequency) {
this.frequency = frequency;
}

@JsonProperty("Range")
public Double getRange() {
return range;
}

@JsonProperty("Range")
public void setRange(Double range) {
this.range = range;
}

@JsonAnyGetter
public Map<String, Object> getAdditionalProperties() {
return this.additionalProperties;
}

@JsonAnySetter
public void setAdditionalProperty(String name, Object value) {
this.additionalProperties.put(name, value);
}

}

Result2.java: Result2.java:

import java.util.HashMap;
import java.util.Map;
import com.fasterxml.jackson.annotation.JsonAnyGetter;
import com.fasterxml.jackson.annotation.JsonAnySetter;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonPropertyOrder;

@JsonInclude(JsonInclude.Include.NON_NULL)
@JsonPropertyOrder({
"Bid",
"Ask",
"Last"
})
public class Result2 {

@JsonProperty("Bid")
private Double bid;
@JsonProperty("Ask")
private Double ask;
@JsonProperty("Last")
private Double last;
@JsonIgnore
private Map<String, Object> additionalProperties = new HashMap<String, Object>();

@JsonProperty("Bid")
public Double getBid() {
return bid;
}

@JsonProperty("Bid")
public void setBid(Double bid) {
this.bid = bid;
}

@JsonProperty("Ask")
public Double getAsk() {
return ask;
}

@JsonProperty("Ask")
public void setAsk(Double ask) {
this.ask = ask;
}

@JsonProperty("Last")
public Double getLast() {
return last;
}

@JsonProperty("Last")
public void setLast(Double last) {
this.last = last;
}

@JsonAnyGetter
public Map<String, Object> getAdditionalProperties() {
return this.additionalProperties;
}

@JsonAnySetter
public void setAdditionalProperty(String name, Object value) {
this.additionalProperties.put(name, value);
}

}

Now you deserialize the JSON using the following piece of code: 现在,使用以下代码反序列化JSON:

ObjectMapper mapper = new ObjectMapper();
    String jsonInString //which contains your json data in string
    Example example= mapper.readValue(jsonInString, Example.class);

Here comes the tricky part, now your map contains the Results response but we are not sure if it is a list of objects or object. 棘手的部分到了,现在您的地图包含“ Results响应,但是我们不确定它是对象列表还是对象列表。

Now to get the Results we will first try to identify if it's a collection or not ( as list is a collection) which will help us identify. 现在要获取Results我们将首先尝试确定它是否是一个集合(因为列表是一个集合),这将有助于我们进行识别。

Object resultObject = example.getAdditionalProperties().getKey("results");

if ( resultObject instanceof Collection<?>){

List<Result1> results=resultObject;
}

else{

Result2 results=resultObject;

}

Hope this solves your issue!! 希望这能解决您的问题!

Let me know if you need clarification with anything!! 让我知道您是否需要任何澄清!

I managed to solve my problem. 我设法解决了我的问题。 I created a ParentNode as suggested by Coder with a generic type. 我按照Coder的建议使用通用类型创建了ParentNode。 This allows any type and even collections to be within result. 这允许结果中包含任何类型,甚至是集合。


Response Class 反应等级

public class Response<T> {

    private boolean success;
    private String message;
    private T result;

    public T getResult() {
        return result;
    }

    public String getMessage () {
       return message;
    }

    public boolean getSuccess() {
        return success;
    }
}


Example Usage 用法示例

 ObjectMapper objectMapper = new ObjectMapper(); // When the result is one object Response<DistanceStat> res = objectMapper.readValue(data, new TypeReference<Response<DistanceStat>>() {}); // For a collection of objects under result Response<Collection<DistanceStat>> res = objectMapper.readValue(data, new TypeReference<Response<Collection<DistanceStat>>>() {}); 

This is an close to an elegant solution I'm looking for now, would now be useful to avoid the triple type defintion in the second usage example. 这与我现在正在寻找的一种优雅的解决方案非常接近,现在将有助于避免第二个用法示例中的三重类型定义。

Note: I'm accepting Coder's answer as it lead to this solution. 注意:我接受Coder的回答,因为它会导致此解决方案。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM