2012-10-31 6 views
5

Attualmente sto cercando di utilizzare Flexjson per deserializzare una stringa JSON e mapparla al modello Object della mia app per Android . L'applicazione è una sorta di libreria con diversi fornitori che possono avere alcuni cataloghi con più cataloghi e documenti al loro interno. JSON vengono recuperati da un servizio web non ho alcuna influenza sulla e simile a questa:Mappare un JSONObject a un elenco con Flexjson in Java/Android

{ 
    "library":{ 
     "vendor":[ 
      { 
       "id":146, 
       "title":"Vendor1", 
       "catalog":[ 
        { 
         "id":847, 
         "document":[ 
          { 
           "id":1628, 
           "title":"Document", 
       ... 
          }, 
          { 
       ... 
          } 
         ], 
         "title":"Catalog ", 
        }, 
       { 
       ... 
       } 
       ] 
      }, 
      { 
      ... 
      } 
     ] 
    } 
} 

Così ogni fornitore, catalogo, il documento è rappresentato da un JSONObject e tutti i cataloghi dei bambini e documenti sono all'interno di un JSONArray. Finora tutto funziona bene con Flexjson e il seguente codice deserializzazione:

LibraryResponse response = new JSONDeserializer<LibraryResponse>() 
        .use(Timestamp.class, new TimestampObjectFactory()) 
        .deserialize(getLocalLibrary(), LibraryResponse.class); 
return response.library; 

Ho un oggetto libreria che ha una List<Vendor>. Ogni venditore ha uno List<Catalog> e uno List<Document>.

Ma sfortunatamente, il servizio Web collega i JSONArrays a semplici JSONObjects se un catalogo contiene un solo documento oppure un catalogo contiene un solo catalogo. Così il JSON in questo caso si presenta così:

"document": 
    { 
     "id":1628, 
     "title":"Document", 
     ... 
    } 

Ora Flexjson non sa come deserializzare e io alla fine con un library.vendorX.getDocument() essendo un List<HashMap> invece di un List<Document>. Un'idea è di dire a Flexjson esplicitamente come gestire questi casi, ma non ho idea di dove cominciare. Un altro modo potrebbe essere quello di analizzare manualmente il json iniziale e sostituire tali JSONObjects con il JSONArray appropriato. Ma penso che in questo modo non sia davvero bello andare, dato che la biblioteca può essere piuttosto profonda.

Spero che tu possa fornire una guida qui.

risposta

1

Questo è un po 'di gnarly json mapping in corso. Cosa ha fatto il codificatore backend ?! #NotHelping.

Bene guardando il codice, Flexjson è codificato per gestire questo fuori dalla scatola. Ma sembra che non stia trasmettendo le informazioni di battitura al binding in modo che non sappia di quale tipo è vincolante, quindi restituisce solo una mappa. È un errore che probabilmente dovrebbe essere corretto. La buona notizia è che c'è un problema con lo.

In ogni caso, la cosa più semplice che posso pensare è installare un oggetto ObjectFactory in tale elenco. Quindi puoi controllare e vedere se ottieni una mappa o un elenco quando lo stream è deserializzato. Quindi puoi racchiuderlo in un elenco e inviarlo al decodificatore appropriato. Qualcosa di simile:

LibraryResponse response = new JSONDeserializer<LibraryResponse>() 
       .use(Timestamp.class, new TimestampObjectFactory()) 
       .use("library.vendor.values.catalog.values.document", new ListDocumentFactory()) 
       .deserialize(getLocalLibrary(), LibraryResponse.class); 

Poi

public class ListDocumentFactory implements ObjectFactory { 

    public Object instantiate(ObjectBinder context, Object value, Type targetType, Class targetClass) { 
     if(value instanceof Collection) { 
      return context.bindIntoCollection((Collection)value, new ArrayList(), targetType); 
     } else { 
      List collection = new ArrayList(); 
      if(targetType instanceof ParameterizedType) { 
       ParameterizedType ptype = (ParameterizedType) targetType; 
       collection.add(context.bind(value, ptype.getActualTypeArguments()[0])); 
      } else { 
       collection.add(context.bind(value)); 
       return collection; 
      } 
     } 
    } 
} 

penso che sia più o meno quello che sarebbe risolvere il bug, ma dovrebbe anche risolvere il problema.

+0

Grazie per la risposta! Penso di non essere stato chiaro, ottengo sempre una lista ma nel caso in cui ci sia un solo documento non ho 'Documenti' nella lista ma' HashMaps', quindi 'Lista ' come' catalog.document' invece di 'Lista '. Gli oggetti mappa hash contengono i dati connessi al documento. Sembra strano per me. Penso di aver bisogno di una fabbrica che decida se abbiamo già un documento o se abbiamo un 'HashMap'. Se quest'ultimo dovessi mappare manualmente l'oggetto documento.Le mie prime prove fallirono, comunque. Pensi che questo approccio sia possibile? –

+0

Non riesco a vedere come la mia risposta non ha risposto al tuo problema. Penso che il motivo per cui stai ricevendo una lista invece che nell'elenco sia un bug in Flexjson. JSONDeserializer prima traduce il JSON in oggetti semplici come Elenco, Mappa, Stringa, Numero e Booleano. Quindi usa una serie di ObjectFactory per mappare quegli oggetti semplici negli oggetti reali in cui stai mappando. Quindi il livello ObjectFactory è prima che abbiamo un qualsiasi oggetto fortemente digitato come Documento. Quindi ti collegherai a quel punto scrivendo il tuo ObjectFactory come ho mostrato invece di usare l'istanza predefinita. – chubbsondubs

+0

Mi dispiace, penso di aver frainteso lì. Ad ogni modo, durante il tentativo di codice sto ricevendo un'eccezione in 'ParameterizedType ptype = (ParameterizedType) targetType;' 'java.lang.ClassCastException: java.lang.Class non può essere lanciato su java.lang.reflect.ParameterizedType'. Un'altra domanda: se si specifica che Factory deve essere utilizzato su 'library.vendor.values.catalog.values.document', non influirà su altri livelli come' library.vendor.values.document'? Come anche un venditore può avere documenti ... Sarebbe possibile specificare la fabbrica da usare su "LibraryItem.class', che è la superclasse di tutti gli altri? –

Problemi correlati