2011-10-05 13 views
39

Iまし以下のクラスGsonハンドルオブジェクトまたは配列

public class MyClass { 
    private List<MyOtherClass> others; 
} 

public class MyOtherClass { 
    private String name; 
} 

持って、私はこの

{ 
    others: { 
    name: "val" 
    } 
} 

またはこの

{ 
    others: [ 
    { 
     name: "val" 
    }, 
    { 
     name: "val" 
    } 
    ] 
} 

私がしたいように見えるかもしれJSONを持っていますこれらのJSON形式の両方に同じMyClassを使用できるようにします。 Gsonでこれを行う方法はありますか?

+1

質問は次のようにJSONを生成し、誰ですか?それは有効なJsonですか?そうであれば、Gsonはそれを処理する必要があります。もしそうでなければ、 "真の"解決策は生産者を修正することでなければならない。 – Nilzor

+5

これはJSONを書く素晴らしい方法ではないことに全く同意します。残念なことに、私たちが消費するデータを常に管理するとは限らないので、プロデューサーを修正することは必ずしもオプションではありません。 JSONはスキーマレスなので、有効なJSONです。 –

答えて

69

私は答えを思いついた。

private static class MyOtherClassTypeAdapter implements JsonDeserializer<List<MyOtherClass>> { 
    public List<MyOtherClass> deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext ctx) { 
     List<MyOtherClass> vals = new ArrayList<MyOtherClass>(); 
     if (json.isJsonArray()) { 
      for (JsonElement e : json.getAsJsonArray()) { 
       vals.add((MyOtherClass) ctx.deserialize(e, MyOtherClass.class)); 
      } 
     } else if (json.isJsonObject()) { 
      vals.add((MyOtherClass) ctx.deserialize(json, MyOtherClass.class)); 
     } else { 
      throw new RuntimeException("Unexpected JSON type: " + json.getClass()); 
     } 
     return vals; 
    } 
} 

TypeTokencom.google.gson.reflect.TypeTokenであることをこの

Type myOtherClassListType = new TypeToken<List<MyOtherClass>>() {}.getType(); 

Gson gson = new GsonBuilder() 
     .registerTypeAdapter(myOtherClassListType, new MyOtherClassTypeAdapter()) 
     .create(); 

ようGsonオブジェクトをインスタンス化。

あなたはここに解決策について読むことができます。https://sites.google.com/site/gson/gson-user-guide#TOC-Serializing-and-Deserializing-Gener

+0

ありがとう、完璧に動作します。 JSONが単一のオブジェクトまたはそれらのセットを返すケースがありました。 – gnosio

+0

ありがとうございます。これは素晴らしい。私は2つの異なるTypeAdapterが必要でしたので、別の.registerTypeAdapterを追加してそれらをチェーンしました。 – tristan2468

+5

なぜGsonは注釈だけを配列やオブジェクトの受け入れに入れないのですか?これは非常に求められています。 –

8

はあなたに解決のためのの三杯をありがとうございました!

それは複数のタイプのために必要だ場合には、一般的なタイプと同じこと:

public class SingleElementToListDeserializer<T> implements JsonDeserializer<List<T>> { 

private final Class<T> clazz; 

public SingleElementToListDeserializer(Class<T> clazz) { 
    this.clazz = clazz; 
} 

public List<T> deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { 
    List<T> resultList = new ArrayList<>(); 
    if (json.isJsonArray()) { 
     for (JsonElement e : json.getAsJsonArray()) { 
      resultList.add(context.<T>deserialize(e, clazz)); 
     } 
    } else if (json.isJsonObject()) { 
     resultList.add(context.<T>deserialize(json, clazz)); 
    } else { 
     throw new RuntimeException("Unexpected JSON type: " + json.getClass()); 
    } 
    return resultList; 
    } 
} 

と設定Gson:

Type myOtherClassListType = new TypeToken<List<MyOtherClass>>() {}.getType(); 
SingleElementToListDeserializer<MyOtherClass> adapter = new SingleElementToListDeserializer<>(MyOtherClass.class); 
Gson gson = new GsonBuilder() 
    .registerTypeAdapter(myOtherClassListType, adapter) 
    .create(); 
0

、三杯は答えるオフの構築、私がすることができます以下のものを持っていますJsonArrayは配列として直接デシリアライズされます。

static public <T> T[] fromJsonAsArray(Gson gson, JsonElement json, Class<T> tClass, Class<T[]> tArrClass) 
     throws JsonParseException { 

    T[] arr; 

    if(json.isJsonObject()){ 
     //noinspection unchecked 
     arr = (T[]) Array.newInstance(tClass, 1); 
     arr[0] = gson.fromJson(json, tClass); 
    }else if(json.isJsonArray()){ 
     arr = gson.fromJson(json, tArrClass); 
    }else{ 
     throw new RuntimeException("Unexpected JSON type: " + json.getClass()); 
    } 

    return arr; 
} 

使用法:

String response = "......."; 

    JsonParser p = new JsonParser(); 
    JsonElement json = p.parse(response); 
    Gson gson = new Gson(); 
    MyQuote[] quotes = GsonUtils.fromJsonAsArray(gson, json, MyQuote.class, MyQuote[].class); 
関連する問題