2011-10-05 15 views
39

Mam następujące klasyGson przedmiot uchwyt lub tablicy

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

public class MyOtherClass { 
    private String name; 
} 

I mam JSON, które mogą wyglądać tak

{ 
    others: { 
    name: "val" 
    } 
} 

lub tym

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

ja lubię móc używać tego samego MyClass dla obu tych formatów JSON. Czy istnieje sposób, aby to zrobić z Gsonem?

+1

Pytanie brzmi, kto generuje JSON w ten sposób? Czy to jest ważne Json? Jeśli tak, Gson powinien sobie z tym poradzić. Jeśli nie, "prawdziwym" rozwiązaniem powinno być naprawienie producenta. – Nilzor

+5

Całkowicie zgadzam się, że nie jest to świetny sposób na napisanie JSON. Niestety, nie zawsze mamy kontrolę nad danymi, które konsumujemy, więc ustalenie producenta nie zawsze jest możliwe. Jest to poprawny JSON, ponieważ JSON nie ma schematu. –

Odpowiedz

69

Wymyśliłem odpowiedź.

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

instancji obiektu Gson jak ten

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

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

To TypeToken jest com.google.gson.reflect.TypeToken.

można przeczytać tutaj o rozwiązanie:

https://sites.google.com/site/gson/gson-user-guide#TOC-Serializing-and-Deserializing-Gener

+0

Dzięki, działa idealnie. Miałem przypadek, w którym JSON zwróciłby pojedynczy obiekt lub ich zestaw. – gnosio

+0

Dzięki. To jest świetne. Potrzebowałem dwóch różnych TypeAdapterów, więc przykręciłem je, dodając kolejny .registerTypeAdapter – tristan2468

+5

Dlaczego Gson nie umieszcza tylko adnotacji, aby zaakceptować tablicę lub obiekt tego samego formatu? Jest to bardzo pożądane. –

8

Dziękuję trzy kubki za rozwiązanie!

samo z typu rodzajowego w przypadku jest to potrzebne dla wielu typów:

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

i konfigurowanie Gson:

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

Budynek off trzy kubki odpowiedzieć, mam następujący która umożliwia JsonArray można deserializować bezpośrednio jako tablicę.

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

Zastosowanie:

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