JAXB:解组异构数组

6
我将使用MOXy来解析以下结构的JSON:

[
  {
    "page": 1,
    "pages": 1
  },
  [
    {
        "indicator": {
            "id": "IC.BUS.EASE.XQ",
            "value": "Ease of doing business index"
        },
        "country": {
            "id": "1A",
            "value": "Arab World"
        },
        "value": "113.952380952381",
        "date": "2014"
    },
    ...
    ]
]

数组的第一个元素是一个对象,第二个元素是另一个由复杂元素组成的数组。我在这里真的很努力地搜索了SO和MOXy文档,但没有找到类似的例子。

我的最佳尝试是将json文档映射到JAVA类,如下所示。根类是CountryDataResponse(省略getter和setter):

@XmlRootElement
@XmlType(propOrder ={"paginationInfo", "dataArray"})
public class CountryDataResponse {
    private DataArray dataArray;
    private PaginationInfo paginationInfo;
}

我能看到这个会失败,因为它不是一个数组,但我完全迷失了方向。

PaginationInfo类模拟了根数组的第一个元素,DataArray类包装了第二个元素,即Data类元素的数组。此外,我还为每个Data元素内部的复杂类型创建了Indicator和Country类。

主要的类(省略了Indicator和Country):

@XmlRootElement(name = "paginationInfo")
@XmlAccessorType(XmlAccessType.FIELD)
public class PaginationInfo {

    private int page;
    private int pages;
}

@XmlRootElement( name = "dataArray" )
public class DataArray {
    List<Data> datas;
}

@XmlRootElement(name="data")
@XmlAccessorType(XmlAccessType.FIELD)
public class Data {
    private Indicator indicator;
    private Country country;
    private String date;
    private double value;
}

现在,调试以下代码:
public static void main(String args[]) {
    String test = "[{\"page\": 1,\"pages\": 1,\"per_page\": \"1000\",\"total\": 248},"
                + "["
                + "{\"indicator\": {\"id\": \"NY.GDP.MKTP.CD\",\"value\": \"GDP (current US$)\"},"
                + "\"country\": {\"id\": \"1A\",\"value\": \"Arab World\"},"
                + "\"value\": \"2853079422103.94\","
                + "\"decimal\": \"1\","
                + "\"date\": \"2013\"},"
                + "{\"indicator\": {\"id\": \"NY.GDP.MKTP.CD\",\"value\": \"GDP (current US$)\"},"
                + "\"country\": {\"id\": \"S3\",\"value\": \"Caribbean small states\"},"
                + "\"value\": \"67033118185.1864\","
                + "\"decimal\": \"1\","
                + "\"date\": \"2013\"}"
                + "]]";

    JAXBContext jc = JAXBContext.newInstance(CountryDataResponse.class, Country.class, Data.class, DataArray.class, Indicator.class, PaginationInfo.class);
    Unmarshaller unmarshaller = jc.createUnmarshaller();
    unmarshaller.setProperty(UnmarshallerProperties.MEDIA_TYPE, MediaType.APPLICATION_JSON);
    unmarshaller.setProperty(UnmarshallerProperties.JSON_INCLUDE_ROOT, false);

    Object res = unmarshaller.unmarshal(json, CountryDataResponse.class);
}
res对象(JAXBElement类)具有ArrayList类型的值。数组的第一个元素CountryDataResponse类的对象(应该是PaginationInfo),第二个元素是另一个ArrayList,其中的元素也是CountryDataResponse类的实例(它们应该是Data实例)。请问是否有人能帮我解决这个问题?或者这只是一个格式不正确的JSON,无法自动反序列化正确?谢谢您提前的帮助。
2个回答

1
尽管JSON是有效的,但我建议更改结构,类似于以下内容:
{
"paginationInfo": {
    "page": 1,
    "pages": 1
},
"dataArray": [
    {
        "indicator": {
            "id": "IC.BUS.EASE.XQ",
            "value": "Ease of doing business index"
        },
        "country": {
            "id": "1A",
            "value": "Arab World"
        },
        "value": "113.952380952381",
        "date": "2014"
    }
]

}

这将允许您使用“key”名称提取所需的数据,这是JSON的预期用法。
另一种方法是在分页对象中嵌入数据数组:
{
"page": 1,
"pages": 1,
"dataArray": [
    {
        "indicator": {
            "id": "IC.BUS.EASE.XQ",
            "value": "Ease of doing business index"
        },
        "country": {
            "id": "1A",
            "value": "Arab World"
        },
        "value": "113.952380952381",
        "date": "2014"
    }
]

}

这种方法可以让你创建一个通用的页面包装器,如果你想要多种格式的页面,这将非常有用。
希望这能有所帮助。

谢谢你的回答。事实上,你的第一个建议是将CountryDataResponse进行编组的结果,所以使用它非常有意义 :) 不幸的是,我无法更改结构:它来自http://api.worldbank.org/countries/indicators/NY.GDP.MKTP.CD?per_page=1000&MRV=1&format=json。 - MrMiyagi
1
在这种情况下,我会考虑为CountryDataResponse对象创建一个自定义序列化器:http://www.baeldung.com/jackson-custom-serialization - robinsio

0

由于 MOXy 在 2.6 版本中添加了一个功能,现在可以从 javax.json.JsonStructure、javax.json.JsonObject 和 javax.json.JsonArray 进行反编组。

使用此功能,我已成功将原始 JSON 的不同部分反编组为两个对象:PaginationInfo 实例和 Data 的 ArrayList。这些对象可以用于配置 CountryDataResponse 的实例,尽管这并不是必需的,因为这个类最初只是为了尝试直接从 JSON 反编组而创建的。

public static CountryDataResponse javaSevenMode(String jsonString) 
    throws PropertyException, JAXBException {

    Unmarshaller unmarshaller = JAXB_CONTEXT.createUnmarshaller();
    unmarshaller.setProperty(UnmarshallerProperties.MEDIA_TYPE, MediaType.APPLICATION_JSON);
    unmarshaller.setProperty(UnmarshallerProperties.JSON_INCLUDE_ROOT, false);

    StringReader sr = new StringReader(jsonString);
    JsonReader jsonReader = Json.createReader(sr);
    JsonArray rootArray = jsonReader.readArray();

    JsonObject paginationInfoJO = rootArray.getJsonObject(0);
    JsonStructureSource paginationInfoJSS = new JsonStructureSource(paginationInfoJO);
    PaginationInfo pi = unmarshaller.unmarshal(paginationInfoJSS, PaginationInfo.class).getValue();

    JsonArray dataJArray = rootArray.getJsonArray(1);
    JsonStructureSource dataArrayJSS = new JsonStructureSource(dataJArray);
    List<Data> datas
            = (List<Data>) unmarshaller.unmarshal(dataArrayJSS, Data.class)
            .getValue();

    DataArray da = new DataArray();
    da.setDatas(datas);

    CountryDataResponse cdr = new CountryDataResponse();
    cdr.setDataArray(da);
    cdr.setPaginationInfo(pi);

    return cdr;
}

感谢@blaise-doughan的启发(请参见http://blog.bdoughan.com/2013/07/eclipselink-moxy-and-java-api-for-json.html


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接