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

时间:2017-02-23 16:49:12

标签: java arrays json jackson

<小时/> 注意:我已经重写了这个问题,事先确定它太过分了,我不知道如何解决这个问题。

我目前正在尝试将RESTful API中的数据反序列化为POJO类。 API的每个方法都返回相同的响应结构,实际结果具有不同的结构,具体取决于方法。我希望能够将每个方法的结果映射到它自己的POJO类。

两个示例JSON响应属于此结构,一个返回一个对象数组,另一个返回一系列属性。

在这种情况下,'result'中的每个JSON对象都应反序列化为它自己的POJO实例。

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

在这种情况下,'result'是对象,应映射到单个POJO实例。

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

这将是与前一个示例不同的类,因为它是来自不同API方法的响应。 我只是想提取结果,任何响应都不需要成功和消息。

2 个答案:

答案 0 :(得分:2)

由于您的results响应是动态的,我建议您不要在反序列化中包含results对象。在您的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);
}

现在名为Map的{​​{1}}将包含您未尝试在Parent对象中捕获的任何其他对象(在这种情况下,它将包含您的additionalProperties对象)。它会根据您的回复存储resultsObject,您可以使用键值list of Objects访问它。

正如 FlemingJp 所建议的那样,使用泛型类型对于这个问题似乎是一个非常可行的解决方案,所以我在这个答案中也包含了这一部分。

results

使用示例

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;
    }
}

修改

您可以按如下方式在jackson中反序列化:

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>>>() {});

ObjectMapper mapper = new ObjectMapper(); String jsonInString //which contains your json data in string ParentNode parentNode = mapper.readValue(jsonInString, ParentNode.class); 是您的父类。

编辑2

PraentNode:这是非常具体的情况。

这些是您需要的POJO类,您必须反序列化的父类

Note

我故意不在此处包含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); } } 课程。现在,无论您获得的Result响应是什么,Result都会Map additional properties作为object存储,可以是list<Result>或类Result

现在,您有Result个对象的两个结构。您可以将它们存储在相同的POJO中。所以让我们为每个结构构建两个不同的POJO类。

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:

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);
}

}

现在使用以下代码反序列化JSON:

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

这是棘手的部分,现在你的地图包含Results响应,但我们不确定它是否是对象列表或对象。

现在要获得Results我们将首先尝试确定它是否是一个集合(因为列表是一个集合),这将有助于我们识别。

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

if ( resultObject instanceof Collection<?>){

List<Result1> results=resultObject;
}

else{

Result2 results=resultObject;

}

希望这能解决你的问题!!

如果您需要澄清任何事情,请告诉我!

答案 1 :(得分:1)

我设法解决了我的问题。我按照编码器的建议使用泛型类型创建了一个ParentNode。这允许任何类型甚至集合都在结果中。

响应类

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;
    }
}

<小时/> 用法示例

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>>>() {});

这是一个接近我现在正在寻找的优雅解决方案,现在可以避免第二个用法示例中的三重类型定义。

注意:我接受了Coder的回答,因为它导致了这个解决方案。