[java] Google Gson: ¿deserializar el objeto de la lista <clase>? (tipo genérico)


Answers

Otra forma es usar una matriz como un tipo, por ejemplo:

MyClass[] mcArray = gson.fromJson(jsonString, MyClass[].class);

De esta forma evitará todas las molestias con el objeto Type, y si realmente necesita una lista, siempre puede convertir la matriz en una lista de la siguiente manera:

List<MyClass> mcList = Arrays.asList(mcArray);

En mi humilde opinión esto es mucho más legible.

Y para que sea una lista real (que se puede modificar, consulte las limitaciones de Arrays.asList() ), haga lo siguiente:

List<MyClass> mcList = new ArrayList<>(Arrays.asList(mcArray));
Question

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

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

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

pero luego aparece un error en eclipse que dice "El tipo nuevo List () {} debe implementar el método abstracto heredado ..." y si uso una solución rápida obtengo un monstruo de más de 20 stubs 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)

Capté JsonParseExceptions y el "resultado" no es nulo.

Comprobé listType con el depurador y obtuve lo siguiente:

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

por lo que parece que la invocación "getClass" no funcionó correctamente. Alguna sugerencia...?

Edit2: He verificado 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), al igual que en el ejemplo, pero no obtuve esa excepción en absoluto. Así que cambié la serialización como se sugiere en la guía del usuario. No ayudó, sin embargo.

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




Consulte el ejemplo 2 para la comprensión de la clase 'Tipo' de Gson.

Ejemplo 1: en este deserilizeResturant utilizamos 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());
    }
}



Al responder a mi pregunta original, acepté la respuesta de doc_180, pero si alguien vuelve a encontrarse con este problema, también responderé la segunda mitad de mi pregunta:

¡El NullPointerError que describí no tenía nada que ver con la Lista en sí, sino con su contenido!

La clase "MyClass" no tenía un constructor "no args", y ninguno tenía una superclase. Una vez que agregué un simple constructor de "MyClass ()" a MyClass y su superclase, todo funcionó bien, incluida la serialización y deserialización de List, tal como sugería doc_180.




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
}

Entonces, para usar:

val type = buildType<YourMagicObject>()



Wep, otra forma de lograr el mismo resultado. Lo usamos para su legibilidad.

En lugar de hacer esta oración difícil de leer:

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

Crea una clase vacía que amplíe una Lista de tu objeto:

public class YourClassList extends ArrayList<YourClass> {}

Y úsala al analizar el JSON:

List<YourClass> list = new Gson().fromJson(jsonArray, YourClassList.class);



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



Links