2016-04-21 28 views
6

ho un po 'strano come JSON:GSON deserializzare matrice JSON con più tipi di oggetti

[ 
    { 
    "type":"0", 
    "value":"my string" 
    }, 
    { 
    "type":"1", 
    "value":42 
    }, 
    { 
    "type":"2", 
    "value": { 
    } 
    } 
] 

Sulla base di qualche campo, l'oggetto nella matrice è un certo tipo. Usando Gson, il mio pensiero è di avere un TypeAdapterFactory che mandi gli adattatori delegati per quei determinati tipi a un TypeAdapter, ma sono costretto a capire un buon modo di leggere quel campo "type" per sapere quale tipo creare. Nel TypeAdapter,

Object read(JsonReader in) throws IOException { 
    String type = in.nextString(); 
    switch (type) { 
    // delegate to creating certain types. 
    } 
} 

potrebbe supporre il campo "tipo" viene prima di tutto nella mia JSON. C'è un modo decente per rimuovere quell'ipotesi?

risposta

8

Ecco un codice che ho scritto per gestire una serie di articoli NewsFeedArticle e NewsFeedAd in Json. Entrambe le voci implementano un'interfaccia marker NewsFeedItem per permettermi di verificare facilmente se TypeAdater debba essere usato per un campo particolare.

public class NewsFeedItemTypeAdapterFactory implements TypeAdapterFactory { 

    @Override 
    @SuppressWarnings("unchecked") 
    public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> type) { 
     if (!NewsFeedItem.class.isAssignableFrom(type.getRawType())) { 
      return null; 
     } 

     TypeAdapter<JsonElement> jsonElementAdapter = gson.getAdapter(JsonElement.class); 
     TypeAdapter<NewsFeedArticle> newsFeedArticleAdapter = gson.getDelegateAdapter(this, TypeToken.get(NewsFeedArticle.class)); 
     TypeAdapter<NewsFeedAd> newsFeedAdAdapter = gson.getDelegateAdapter(this, TypeToken.get(NewsFeedAd.class)); 

     return (TypeAdapter<T>) new NewsFeedItemTypeAdapter(jsonElementAdapter, newsFeedArticleAdapter, newsFeedAdAdapter).nullSafe(); 
    } 

    private static class NewsFeedItemTypeAdapter extends TypeAdapter<NewsFeedItem> { 

     private final TypeAdapter<JsonElement> jsonElementAdapter; 
     private final TypeAdapter<NewsFeedArticle> newsFeedArticleAdapter; 
     private final TypeAdapter<NewsFeedAd> newsFeedAdAdapter; 

     NewsFeedItemTypeAdapter(TypeAdapter<JsonElement> jsonElementAdapter, 
       TypeAdapter<NewsFeedArticle> newsFeedArticleAdapter, 
       TypeAdapter<NewsFeedAd> newsFeedAdAdapter) { 
      this.jsonElementAdapter = jsonElementAdapter; 
      this.newsFeedArticleAdapter = newsFeedArticleAdapter; 
      this.newsFeedAdAdapter = newsFeedAdAdapter; 
     } 

     @Override 
     public void write(JsonWriter out, NewsFeedItem value) throws IOException { 
      if (value.getClass().isAssignableFrom(NewsFeedArticle.class)) { 
       newsFeedArticleAdapter.write(out, (NewsFeedArticle) value); 

      } else if (value.getClass().isAssignableFrom(NewsFeedAd.class)) { 
       newsFeedAdAdapter.write(out, (NewsFeedAd) value); 

      } 

     } 

     @Override 
     public NewsFeedItem read(JsonReader in) throws IOException { 
      JsonObject objectJson = jsonElementAdapter.read(in).getAsJsonObject(); 

      if (objectJson.has("Title")) { 
       return newsFeedArticleAdapter.fromJsonTree(objectJson); 

      } else if (objectJson.has("CampaignName")) { 
       return newsFeedAdAdapter.fromJsonTree(objectJson); 
      } 

      return null; 
     } 
    } 
} 

È possibile quindi registrare questo con GSON utilizzando il seguente codice.

return new GsonBuilder() 
     .registerTypeAdapterFactory(new NewsFeedItemTypeAdapterFactory()) 
     .create(); 
+0

Grazie Jake per aver reso il codice migliore. –

+1

Sì, buon esempio anche! –

Problemi correlati