JAXB: Unmarshal heterogeneous array

I am trying to disable the use of MOXy 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 is another array of complex elements. I really searched here in SO and the MOXy documentation for a simple example without any success.

My best attempt to map a json document to JAVA classes is as follows. The root class is CountryDataResponse (getters and seters ommited):

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

(I see this happen because it is not an array, but I am completely lost.)

The PaginationInfo class models the first element of the root array, and the DataArray class wraps the second element, which is an element of the Array of Data class. In addition, I created the Indicator and Country classes for complex types within each Data element.

Main classes (indicator and country are highlighted):

 @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 debug 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 the JAXBElement class) has a value of type ArrayList . the first element of the array is an object of the CountryDataResponse class (it must be PaginationInfo ), the second is another ArrayList with the elements of the CountryDataResponse class (they must Data ).

Can someone help me please, or is it just json garbled and it cannot be automatically unrouted correctly?

Thanks in advance.

+6
source share
2 answers

Thanks to the MOXy feature added in version 2.6, you can disable javax.json.JsonStructure, javax.json.JsonObject and javax.json.JsonArray.

Using this function, I managed to decouple the different parts of the original JSON to two objects: an instance of PaginationInfo and an ArrayList from Data. These objects can then be used to set up an instance of CountryDataResponse, although this would not be necessary since this class was created only to try to disable JSON in the first place.

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

Thanks to @ blaise-doughan for inspiration (see http://blog.bdoughan.com/2013/07/eclipselink-moxy-and-java-api-for-json.html )

0
source

Although JSON is valid, I would suggest changing the structure, something like strings:

 { "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 retrieve the data you want using the name of the "key" that JSON should use.

Another approach would be to embed a data array into an unloaded 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 will allow you to create a general page wrapper that can be useful if you have several formats that you would like to place on the page.

Hope this helps.

+1
source

Source: https://habr.com/ru/post/986962/


All Articles