2016-04-21 3 views
6

Ich habe einige ungerade JSON wie:Gson deserialisieren JSON Array mit mehreren Objekttypen

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

auf irgendeinem Feld basiert, das Objekt in der Anordnung ist eine bestimmte Art. Mit Gson denke ich daran, eine TypeAdapterFactory zu haben, die Delegate-Adapter für diese bestimmten Typen an einen TypeAdapter sendet, aber ich bin aufgehört zu verstehen, wie man dieses "type" -Feld liest, um zu wissen, welcher Typ erstellt werden soll. Im TypeAdapter,

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

würde das Feld "Typ" steht an erster Stelle in meinem JSON übernehmen. Gibt es einen vernünftigen Weg, diese Annahme zu entfernen?

Antwort

8

Hier ist ein Code, den ich schrieb, um eine Reihe von NewsFeedArticle und NewsFeedAd Artikel in Json zu behandeln. Beide Elemente implementieren eine Markierschnittstelle NewsFeedItem, die es mir ermöglicht, problemlos zu überprüfen, ob der TypeAdater für ein bestimmtes Feld verwendet werden soll.

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

Sie können dies dann mit dem folgenden Code bei Gson registrieren.

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

Danke Jake für die Verbesserung des Codes. –

+1

Ja, gutes Beispiel auch! –

Verwandte Themen