java json - Google Gson - deserialize list <class> object? (tipo genérico)




7 Answers

Método para deserializar colección genérica:

import java.lang.reflect.Type;
import com.google.gson.reflect.TypeToken;

...

Type listType = new TypeToken<ArrayList<YourClass>>(){}.getType();
List<YourClass> yourClassList = new Gson().fromJson(jsonArray, listType);

Como varias personas en los comentarios lo han mencionado, aquí hay una explicación de cómo se está utilizando la clase TypeToken . La new TypeToken<...>() {}.getType() construcción new TypeToken<...>() {}.getType() captura un tipo de tiempo de compilación (entre < y > ) en un objeto java.lang.reflect.Type en tiempo de ejecución. A diferencia de un objeto de Class , que solo puede representar un tipo sin procesar (borrado), el objeto de Type puede representar cualquier tipo en el lenguaje Java, incluida una instanciación parametrizada de un tipo genérico.

La clase TypeToken sí no tiene un constructor público, porque se supone que no debe construirlo directamente. En su lugar, siempre construye una subclase anónima (de ahí la {} , que es una parte necesaria de esta expresión).

Debido al borrado de tipos, la clase TypeToken solo puede capturar tipos que son completamente conocidos en tiempo de compilación. (Es decir, no puede hacer un new TypeToken<List<T>>() {}.getType() para un parámetro de tipo T ).

Para obtener más información, consulte la documentación de la clase TypeToken .

of objects

Quiero transferir un objeto de lista a través de Google Gson, pero no sé cómo deserializar tipos genéricos.

Lo que intenté después de mirar this (respuesta de BalusC):

MyClass mc = new Gson().fromJson(result, new List<MyClass>(){}.getClass());

pero luego aparece un error en el eclipse que dice "El nuevo tipo de lista () {} debe implementar el método abstracto heredado ..." y si uso una solución rápida, obtengo un monstruo de más de 20 talones de métodos.

Estoy bastante seguro de que hay una solución más fácil, ¡pero parece que no puedo encontrarla!

Editar:

Ahora tengo

Type listType = new TypeToken<List<MyClass>>()
                {
                }.getType();

MyClass mc = new Gson().fromJson(result, listType);

Sin embargo, obtengo la siguiente excepción en la línea "fromJson":

java.lang.NullPointerException
at org.apache.harmony.luni.lang.reflect.ListOfTypes.length(ListOfTypes.java:47)
at org.apache.harmony.luni.lang.reflect.ImplForType.toString(ImplForType.java:83)
at java.lang.StringBuilder.append(StringBuilder.java:203)
at com.google.gson.JsonDeserializerExceptionWrapper.deserialize(JsonDeserializerExceptionWrapper.java:56)
at com.google.gson.JsonDeserializationVisitor.invokeCustomDeserializer(JsonDeserializationVisitor.java:88)
at com.google.gson.JsonDeserializationVisitor.visitUsingCustomHandler(JsonDeserializationVisitor.java:76)
at com.google.gson.ObjectNavigator.accept(ObjectNavigator.java:106)
at com.google.gson.JsonDeserializationContextDefault.fromJsonArray(JsonDeserializationContextDefault.java:64)
at com.google.gson.JsonDeserializationContextDefault.deserialize(JsonDeserializationContextDefault.java:49)
at com.google.gson.Gson.fromJson(Gson.java:568)
at com.google.gson.Gson.fromJson(Gson.java:515)
at com.google.gson.Gson.fromJson(Gson.java:484)
at com.google.gson.Gson.fromJson(Gson.java:434)

Capturo JsonParseExceptions y el "resultado" no es nulo.

Verifiqué listType con el depurador y obtuve lo siguiente:

  • Tipo de lista
    • args = ListOfTypes
      • list = null
      • resolverTypes = Tipo [1]
    • loader = PathClassLoader
    • ownerType0 = null
    • ownerTypeRes = null
    • rawType = Class (java.util.ArrayList)
    • rawTypeName = "java.util.ArrayList"

así que parece que la invocación "getClass" no funcionó correctamente. Alguna sugerencia...?

Edit2: He comprobado en la Guía del usuario de Gson . Menciona una excepción de tiempo de ejecución que debería ocurrir durante el análisis de un tipo genérico a Json. Lo hice "mal" (no se muestra arriba), como en el ejemplo, pero no obtuve esa excepción. Así que cambié la serialización como en la guía del usuario sugerida. Sin embargo, no ayudó.

Edit3: resuelto, ver mi respuesta a continuación.




Consulte este post. Tipo genérico de Java como argumento para GSON

Tengo mejor solución para esto. Aquí está la clase de envoltorio para la lista, de modo que el envoltorio pueda almacenar exactamente el tipo de lista.

public class ListOfJson<T> implements ParameterizedType
{
  private Class<?> wrapped;

  public ListOfJson(Class<T> wrapper)
  {
    this.wrapped = wrapper;
  }

  @Override
  public Type[] getActualTypeArguments()
  {
      return new Type[] { wrapped };
  }

  @Override
  public Type getRawType()
  {
    return List.class;
  }

  @Override
  public Type getOwnerType()
  {
    return null;
  }
}

Y luego, el código puede ser simple:

public static <T> List<T> toList(String json, Class<T> typeClass)
{
    return sGson.fromJson(json, new ListOfJson<T>(typeClass));
}



public static final <T> List<T> getList(final Class<T[]> clazz, final String json)
{
    final T[] jsonToObject = new Gson().fromJson(json, clazz);

    return Arrays.asList(jsonToObject);
}

Ejemplo:

getList(MyClass[].class, "[{...}]");



Aquí hay una solución que funciona con un tipo definido dinámicamente. El truco es crear el tipo correcto de matriz usando Array.newInstance ().

    public static <T> List<T> fromJsonList(String json, Class<T> clazz) {
    Object [] array = (Object[])java.lang.reflect.Array.newInstance(clazz, 0);
    array = gson.fromJson(json, array.getClass());
    List<T> list = new ArrayList<T>();
    for (int i=0 ; i<array.length ; i++)
        list.add(clazz.cast(array[i]));
    return list; 
}



Para Kotlin simplemente:

import java.lang.reflect.Type
import com.google.gson.reflect.TypeToken
...
val type = object : TypeToken<ArrayList<T>>() {}.type

o, aquí hay una función útil:

fun <T> buildType(): Type {
    return object : TypeToken<ArrayList<T>>() {}.type
}

Luego, utilizar:

val type = buildType<YourMagicObject>()



Me gustó la respuesta de kays1 pero no pude implementarla. Así que construí mi propia versión usando su concepto.

public class JsonListHelper{
    public static final <T> List<T> getList(String json) throws Exception {
        Gson gson = new GsonBuilder().setDateFormat("yyyy-MM-dd HH:mm:ss").create();
        Type typeOfList = new TypeToken<List<T>>(){}.getType();
        return gson.fromJson(json, typeOfList);
    }
}

Uso:

List<MyClass> MyList= JsonListHelper.getList(jsonArrayString);



Consulte el ejemplo 2 para entender la clase de 'Tipo' de Gson.

Ejemplo 1: en este deserilizeResturant usamos la matriz Employee [] y obtenemos los detalles

public static void deserializeResturant(){

       String empList ="[{\"name\":\"Ram\",\"empId\":1},{\"name\":\"Surya\",\"empId\":2},{\"name\":\"Prasants\",\"empId\":3}]";
       Gson gson = new Gson();
       Employee[] emp = gson.fromJson(empList, Employee[].class);
       int numberOfElementInJson = emp.length();
       System.out.println("Total JSON Elements" + numberOfElementInJson);
       for(Employee e: emp){
           System.out.println(e.getName());
           System.out.println(e.getEmpId());
       }
   }

Ejemplo 2:

//Above deserilizeResturant used Employee[] array but what if we need to use List<Employee>
public static void deserializeResturantUsingList(){

    String empList ="[{\"name\":\"Ram\",\"empId\":1},{\"name\":\"Surya\",\"empId\":2},{\"name\":\"Prasants\",\"empId\":3}]";
    Gson gson = new Gson();

    // Additionally we need to se the Type then only it accepts List<Employee> which we sent here empTypeList
    Type empTypeList = new TypeToken<ArrayList<Employee>>(){}.getType();


    List<Employee> emp = gson.fromJson(empList, empTypeList);
    int numberOfElementInJson = emp.size();
    System.out.println("Total JSON Elements" + numberOfElementInJson);
    for(Employee e: emp){
        System.out.println(e.getName());
        System.out.println(e.getEmpId());
    }
}



Related