Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

JAXB: Unmarshal heterogeneous array

I'm trying to unmarshal using MOXy a json with the following structure:

[
  {
    "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"
    },
    ...
    ]
]

The first element of the array is an object and the second element is another array of complex elements. I've really searched here at SO and the MOXy documentation for a simmilar example without any success.

My best attempt at mapping the json document to JAVA classes is as follows. The root class is CountryDataResponse (getters & setters ommited):

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

(I can see this is going to fail, because it isn't an array, but I'm completly lost.)

PaginationInfo class models the first element of the root array and DataArray class wraps the second element, which is an Array of Data class elements. Additionally, I've created the Indicator and Country classes for the complex types inside each Data element.

The main classes (Indicator and Country ommited):

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

Now, debugging the following code:

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

The res object (of class JAXBElement) has a value of type ArrayList. The first element of the array is an object of class CountryDataResponse (it should be PaginationInfo), the second is another ArrayList with elements of class CountryDataResponse, too (they should be Data instances).

Can anyone help me, please, or it is simply a malformed json and it can't be automatically unmarshalled correctly?

Thank you in advance.

like image 546
MrMiyagi Avatar asked May 11 '15 10:05

MrMiyagi


1 Answers

Although the JSON is valid I would suggest changing the structure, something along the lines of:

{
"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"
    }
]

}

This will allow you to extract the data you wish using the 'key' name which is how JSON is intended to be used.

Another approach would be to embed the data array within the paged object:

{
"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"
    }
]

}

This approach would allow you to create a generic page wrapper which could come in useful if you have multiple formats you would like to page.

Hope this helps.

like image 194
robinsio Avatar answered Nov 04 '22 06:11

robinsio