2012-03-22 2 views
53

Ho una classe Java MyPojo che mi interessa deserializzare da JSON. Ho configurato una speciale classe MixIn, MyPojoDeMixIn, per aiutarmi con la deserializzazione. MyPojo ha solo int e String variabili di istanza combinate con getter e setter appropriati. MyPojoDeMixIn sembra qualcosa di simile:Deserializzare JSON in ArrayList <POJO> utilizzando Jackson

public abstract class MyPojoDeMixIn { 
    MyPojoDeMixIn(
     @JsonProperty("JsonName1") int prop1, 
     @JsonProperty("JsonName2") int prop2, 
     @JsonProperty("JsonName3") String prop3) {} 
} 

Nel mio client di prova che faccio quanto segue, ma naturalmente non funziona in fase di compilazione perché c'è un JsonMappingException relativa a un tipo non corrispondente.

ObjectMapper m = new ObjectMapper(); 
m.getDeserializationConfig().addMixInAnnotations(MyPojo.class,MyPojoDeMixIn.class); 
try { ArrayList<MyPojo> arrayOfPojo = m.readValue(response, MyPojo.class); } 
catch (Exception e) { System.out.println(e) } 

Sono consapevole che avrei potuto alleviare questo problema creando un oggetto "risposta" che ha solo un ArrayList<MyPojo> in essa, ma poi avrei dovuto creare questi oggetti un po 'inutile per ogni singolo tipo voglio tornare .

Ho anche guardato in linea JacksonInFiveMinutes ma ho avuto un pessimo tempo a capire le cose su Map<A,B> e come si riferisce al mio problema. Se non puoi dirlo, sono completamente nuovo in Java e provengo da uno sfondo Obj-C. Essi indicano in particolare:

Oltre al legame POJO e tipi "semplici", c'è un ulteriore variante: quella di legare ai contenitori generici (tipizzati). Questo caso richiede una gestione speciale a causa della cosiddetta Type Erasure (utilizzata da Java per implementare i generici in modo leggermente compatibile all'indietro ), che impedisce di utilizzare qualcosa come Collection.class (che non viene compilato).

Quindi, se si desidera associare i dati in una mappa è necessario utilizzare:

Map<String,User> result = mapper.readValue(src, new TypeReference<Map<String,User>>() { }); 

Come posso deserializzare direttamente a ArrayList?

risposta

101

È possibile deserializzare direttamente a un elenco utilizzando il wrapper TypeReference. Un metodo esempio:

public static <T> T fromJSON(final TypeReference<T> type, 
     final String jsonPacket) { 
    T data = null; 

    try { 
     data = new ObjectMapper().readValue(jsonPacket, type); 
    } catch (Exception e) { 
     // Handle the problem 
    } 
    return data; 
} 

e viene usato in questo modo:

final String json = ""; 
Set<POJO> properties = fromJSON(new TypeReference<Set<POJO>>() {}, json); 

.

TypeReference Javadoc

+0

La risposta sembra essere correlata alla loro informazioni su come utilizzare il supporto integrato per 'TypeReference' - Io proprio non capisco come si fa ... Si prega di vedere la mia modifica sopra per le loro istruzioni su come usare i generici. –

+0

Beh, è ​​correlato. Ma questo è un frammento di codice in lavorazione in produzione. Dimentica il tuo mixin, usa solo il codice che ho mostrato (ma sostituisci POJO ovviamente con il nome della tua classe bean effettiva). – Perception

+0

Il tuo codice è stato compilato, ma ottengo un'eccezione di run time durante il tentativo di stampare 'arrayList.toString()' su un 'NullPointerException'. Immagino che questo potrebbe essere dovuto al fatto che il mio 'POJO' non è conforme alle giuste convenzioni di denominazione per le sue proprietà, cioè, l'intero problema è che il servizio web restituisce' Prop1Member' e il mio oggetto ha 'Prop1'. Questa è l'unica vera ragione per cui sto usando i mixin, quindi non devo mettere le dichiarazioni per '@ JsonProperty' nei miei oggetti puri. –

3

Inoltre sto avendo lo stesso problema. Ho un json che deve essere convertito in ArrayList.

L'account è simile a questo.

Account{ 
    Person p ; 
    Related r ; 

} 

Person{ 
    String Name ; 
    Address a ; 
} 

Tutte le classi di cui sopra sono stati annotati correttamente. Ho provato TypeReference>() {} ma non funziona.

Mi dà Arraylist ma ArrayList ha un linkHashMap che contiene alcune hashmaps più collegate contenenti valori finali.

Il mio codice è il seguente:

public T unmarshal(String responseXML,String c) 
{ 
    ObjectMapper mapper = new ObjectMapper(); 

    AnnotationIntrospector introspector = new JacksonAnnotationIntrospector(); 

    mapper.getDeserializationConfig().withAnnotationIntrospector(introspector); 

    mapper.getSerializationConfig().withAnnotationIntrospector(introspector); 
    try 
    { 
     this.targetclass = (T) mapper.readValue(responseXML, new TypeReference<ArrayList<T>>() {}); 
    } 
    catch (JsonParseException e) 
    { 
     e.printStackTrace(); 
    } 
    catch (JsonMappingException e) { 
     e.printStackTrace(); 
    } catch (IOException e) { 
     e.printStackTrace(); 
    } 

    return this.targetclass; 
} 

ho finalmente risolto il problema. Sono in grado di convertire l'elenco in JSON String direttamente al ArrayList come segue:

JsonMarshallerUnmarshaller<T>{ 

    T targetClass ; 

    public ArrayList<T> unmarshal(String jsonString) 
    { 
     ObjectMapper mapper = new ObjectMapper(); 

     AnnotationIntrospector introspector = new JacksonAnnotationIntrospector(); 

     mapper.getDeserializationConfig().withAnnotationIntrospector(introspector); 

     mapper.getSerializationConfig().withAnnotationIntrospector(introspector); 
     JavaType type = mapper.getTypeFactory(). 
        constructCollectionType(ArrayList.class, targetclass.getClass()) ; 
     try 
     { 
     Class c1 = this.targetclass.getClass() ; 
     Class c2 = this.targetclass1.getClass() ; 
      ArrayList<T> temp = (ArrayList<T>) mapper.readValue(jsonString, type); 
     return temp ; 
     } 
     catch (JsonParseException e) 
     { 
     e.printStackTrace(); 
     } 
     catch (JsonMappingException e) { 
      e.printStackTrace(); 
     } catch (IOException e) { 
      e.printStackTrace(); 
     } 

    return null ; 
    } 

} 
48

Un altro modo è quello di utilizzare un array come un tipo, ad esempio:

ObjectMapper objectMapper = new ObjectMapper(); 
MyPojo[] pojos = objectMapper.readValue(json, MyPojo[].class); 

In questo modo si evita tutti i problemi con l'oggetto tipo, e se si ha realmente bisogno di un elenco si può sempre convertire la matrice in un elenco da:

List<MyPojo> pojoList = Arrays.asList(pojos); 

IMHO questo è molto più leggibile.

E per rendere essere un elenco effettivo (che possono essere modificati, vedere limitazioni di Arrays.asList()) poi basta effettuare le seguenti operazioni:

List<MyPojo> mcList = new ArrayList<>(Arrays.asList(pojos)); 
+2

Questa dovrebbe essere la risposta accettata, semplice e molto più leggibile. – dic19

+0

Concordato^Questo è stato molto più utile – cstaikos

7

Questa variante sembra più semplice ed elegante.

CollectionType typeReference = 
    TypeFactory.defaultInstance().constructCollectionType(List.class, Dto.class); 
List<Dto> resultDto = objectMapper.readValue(content, typeReference);