2011-10-05 3 views
39

Я получил следующие классыGson дескриптор объекта или массива

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

public class MyOtherClass { 
    private String name; 
} 

И у меня есть JSON, что может выглядеть как этот

{ 
    others: { 
    name: "val" 
    } 
} 

или этого

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

Я бы чтобы иметь возможность использовать один и тот же MyClass для обоих этих форматов JSON. Есть ли способ сделать это с Гсеном?

+1

Вопрос в том, кто генерирует JSon, как это? Действительно ли это Json? Если это так, Гессон должен справиться с этим. Если нет, «реальным» решением должно быть исправление производителя. – 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; 
    } 
} 

Инстанцировать объект Gson как этот

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

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

Это TypeToken является com.google.gson.reflect.TypeToken.

Вы можете прочитать о решении здесь:

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

+0

Спасибо, отлично работает. У меня был случай, когда JSON вернул бы один объект или набор из них. – gnosio

+0

Спасибо. Отлично. Мне нужно было два разных типа адаптера, поэтому я их приковал, добавив еще один .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);