2016-04-21 6 views
6

У меня есть некоторые нечетные JSON как:Gson десериализации JSON массив с несколькими типами объектов

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

Основываясь на некотором поле, объект в массиве определенного типа. Использование Gson, я думаю, должен иметь TypeAdapterFactory, который отправляет адаптеры делегатов для этих определенных типов в TypeAdapter, но я повесил трубку на понимание хорошего способа чтения этого поля типа, чтобы узнать, какой тип создать. В TypeAdapter,

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

бы предположить поле "тип" приходит первым в моем формате JSON. Есть ли достойный способ снять это предположение?

ответ

8

Вот код, который я написал для обработки массива статей NewsFeedArticle и NewsFeedAd в Json. Оба элемента реализуют интерфейс маркера NewsFeedItem, чтобы я мог легко проверить, следует ли использовать TypeAdater для определенного поля.

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

Вы можете зарегистрировать это в Gson используя следующий код.

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

Спасибо Джейку за то, что вы сделали код лучше. –

+1

Да, хороший пример тоже! –