tutorial serialize objects example array java json generics gson

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



json list to java list gson (13)

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

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.


Como responde a mi pregunta original, he aceptado la respuesta de doc_180, pero si alguien vuelve a tener este problema, también responderé la segunda parte 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 su superclase. Una vez que agregué un simple constructor "MyClass ()" a MyClass y su superclase, todo funcionó bien, incluida la serialización y deserialización de listas según lo sugerido por doc_180.


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


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


Desde Gson 2.8 , podemos crear una función util como

public <T> List<T> getList(String jsonArray, Class<T> clazz) { Type typeOfT = TypeToken.getParameterized(List.class, clazz).getType(); return new Gson().fromJson(jsonArray, typeOfT); }

Ejemplo usando

String jsonArray = ... List<User> user = getList(jsonArray, User.class);


En la respuesta de My case @ uncaught_exceptions no funcionó, tuve que usar List.class lugar de java.lang.reflect.Type :

String jsonDuplicatedItems = request.getSession().getAttribute("jsonDuplicatedItems").toString(); List<Map.Entry<Product, Integer>> entries = gson.fromJson(jsonDuplicatedItems, List.class);


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 .


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


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

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

De esta manera, evitará toda la molestia con el objeto Tipo, 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() ) y luego haga lo siguiente:

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


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


Quiero añadir para una posibilidad más. Si no desea utilizar TypeToken y desea convertir la matriz de objetos json en un ArrayList, puede proceder de la siguiente manera:

Si tu estructura json es como:

{ "results": [ { "a": 100, "b": "value1", "c": true }, { "a": 200, "b": "value2", "c": false }, { "a": 300, "b": "value3", "c": true } ]

}

y tu estructura de clase es como:

public class ClassName implements Parcelable { public ArrayList<InnerClassName> results = new ArrayList<InnerClassName>(); public static class InnerClassName { int a; String b; boolean c; } }

entonces puedes analizarlo como

Gson gson = new Gson(); final ClassName className = gson.fromJson(data, ClassName.class); int currentTotal = className.results.size();

Ahora puedes acceder a cada elemento del objeto className.


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

En lugar de hacer esta frase difícil de leer:

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

Cree una clase vacía que amplíe una lista de su objeto:

public class YourClassList extends ArrayList<YourClass> {}

Y úselo al analizar el JSON:

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


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, "[{...}]");