2015-05-11 7 views
6

Ich versuche moxy eine json mit der folgenden Struktur zu verwenden unmarshal:JAXB: Abstellungs heterogenes Array

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

Das erste Element des Arrays ein Objekt ist und das zweite Element ist ein weiteres Array von komplexen Elementen. Ich habe hier wirklich SO und die MOXy-Dokumentation für ein ähnliches Beispiel ohne Erfolg durchsucht.

Mein bester Versuch, das JSON-Dokument zu JAVA-Klassen zuzuordnen, ist wie folgt. Die Wurzelklasse ist CountryDataResponse (Getter & Setter ommited):

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

(. Ich kann sehen, dies ist zum Scheitern verurteilt, weil es nicht ein Array ist, aber ich bin völlig verloren)

PaginationInfo class modelliert das erste Element des Stammarrays, und die DataArray-Klasse umschließt das zweite Element, das ein Array von Data-Klassenelementen ist. Außerdem habe ich die Indikator- und Länderklassen für die komplexen Typen in jedem Datenelement erstellt.

Die Hauptklassen (Indikator und Land 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; 
} 

Nun Debuggen den folgenden 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); 
} 

Das Objekt res (der Klasse JAXBElement) hat einen Wert vom Typ ArrayList. Das erste Element des Arrays ist ein Objekt der Klasse CountryDataResponse (it sollte PaginationInfo sein), die zweite ist eine weitere Array mit Elementen von Klasse CountryDataResponse, auch (sie sollte sein Daten Instanzen).

Kann mir bitte jemand helfen, oder ist es einfach ein missgebildeter JSON und kann nicht automatisch korrekt demarshaliert werden?

Vielen Dank im Voraus.

Antwort

0

Dank einer in Version 2.6 hinzugefügten MOXy-Funktion ist es möglich, aus javax.json.JsonStructure, javax.json.JsonObject und javax.json.JsonArray zu entpacken.

Mit dieser Funktion habe ich es geschafft, die verschiedenen Teile des ursprünglichen JSON auf zwei Objekte zu entpacken: eine PaginationInfo-Instanz und eine ArrayList von Data. Diese Objekte können dann verwendet werden, um eine Instanz von CountryDataResponse zu konfigurieren, obwohl es nicht notwendig wäre, da diese Klasse erstellt wurde, um zuerst direkt aus dem JSON zu entpacken.

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

Dank @blaise-doughan für Inspiration (siehe http://blog.bdoughan.com/2013/07/eclipselink-moxy-and-java-api-for-json.html)

1

Obwohl die JSON gültig ist, ich würde vorschlagen, die Struktur, die etwas entlang der Linien ändern:

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

}

Dies ermöglicht es Ihnen, die Daten, die Sie den ‚Schlüssel‘ Name Wunsch unter Verwendung zu extrahieren So soll JSON verwendet werden.

würde Ein weiterer Ansatz, die Daten-Array innerhalb des ausgelagerten Objekt einzubetten:

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

}

Dieser Ansatz Sie eine generische Seite Wrapper erstellen würde es ermöglichen, die als nützlich erweisen könnte, wenn Sie mehrere haben Formate, die Sie gerne anzeigen möchten.

Hoffe, das hilft.

+0

Vielen Dank für Ihre Antwort. In der Tat ist Ihr erster Vorschlag das Ergebnis einer CountryDataResponse, so wie es jetzt ist, so dass es sehr sinnvoll wäre, sie zu verwenden :) Leider kann ich die Struktur nicht ändern: sie kommt von http://api.worldbank.org/ Länder/Indikatoren/NY.GDP.MKTP.CD? per_page = 1000 & MRV = 1 & format = json. – MrMiyagi

+1

In diesem Fall würde ich einen benutzerdefinierten Serializer für das CountryDataResponse-Objekt erstellen: http://www.baeldung.com/jackson-custom-serialization – robinsio