2011-10-05 13 views
39

Tengo las siguientes clasesGson maneta objeto o matriz

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

public class MyOtherClass { 
    private String name; 
} 

Y tengo JSON que puede tener este aspecto

{ 
    others: { 
    name: "val" 
    } 
} 

o esta

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

que había gustaría poder usar el mismo MyClass para ambos formatos JSON. ¿Hay alguna manera de hacer esto con Gson?

+1

La pregunta es, que genera JSON como este? ¿Es válido Json? Si es así, Gson debería manejarlo. Si no, la solución "real" debería ser arreglar al productor. – Nilzor

+5

Estoy totalmente de acuerdo en que esta no es una gran manera de escribir JSON. Desafortunadamente, no siempre tenemos control sobre los datos que consumimos, por lo que corregir al productor no siempre es una opción. Es JSON válido, ya que JSON no tiene esquemas. –

Respuesta

69

Encontré una respuesta.

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

una instancia de un objeto como éste Gson

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

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

Eso TypeToken es una com.google.gson.reflect.TypeToken.

Usted puede leer acerca de la solución aquí:

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

+0

Gracias, funciona perfectamente. Tuve un caso donde el JSON devolvería un solo objeto o conjunto de ellos. – gnosio

+0

Gracias. Esto es genial. Necesitaba dos TypeAdapters diferentes, así que los encadené agregando otro .registerTypeAdapter – tristan2468

+5

¿Por qué Gson no está poniendo solo una anotación para aceptar una matriz u objeto del mismo formato? Esto es muy demandado. –

8

Gracias tres copas para la solución!

Lo mismo con el tipo genérico en el caso de que sea necesario para múltiples tipos:

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

y configurar GSON:

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

edificio fuera del tres tazas responder, tengo los siguientes, que permite al JsonArray se deserializará directamente como una matriz.

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

Uso:

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