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 esto (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 new 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étodo.
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)
Yo hago JsonParseExceptions de captura y "número" no es nulo.
Verifiqué listType con el depurador y obtuve lo siguiente:
- tipo de lista
- args = ListOfTypes
- lista = nulo
- resolveTypes = Tipo [1]
- cargador = PathClassLoader
- ownerType0 = nulo
- ownerTypeRes = nulo
- rawType = Class (java.util.ArrayList)
- rawTypeName = "java.util.ArrayList"
- args = ListOfTypes
entonces 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 en absoluto. Así que cambié la serialización como se sugiere en la guía del usuario. Sin embargo, no ayudó.
Edit3: Resuelto, mira mi respuesta a continuación.
TokenType
. ¿Has intentado de esa manera?Respuestas:
Método para deserializar la colección genérica:
Dado que varias personas en los comentarios lo han mencionado, aquí hay una explicación de cómo
TypeToken
se usa la clase. La construcciónnew TypeToken<...>() {}.getType()
captura un tipo de tiempo de compilación (entre el<
y>
) en unjava.lang.reflect.Type
objeto de tiempo de ejecución . A diferencia de unClass
objeto, que solo puede representar un tipo sin formato (borrado), elType
objeto puede representar cualquier tipo en el lenguaje Java, incluida una instanciación parametrizada de un tipo genérico.La
TypeToken
clase en sí no tiene un constructor público, porque no se supone que lo construyas directamente. En su lugar, siempre construye una subclase anónima (de ahí{}
que sea una parte necesaria de esta expresión).Debido a la eliminación de tipos, la
TypeToken
clase solo puede capturar tipos que son completamente conocidos en tiempo de compilación. (Es decir, no se puede hacernew TypeToken<List<T>>() {}.getType()
para un parámetro de tipoT
).Para obtener más información, consulte la documentación de la
TypeToken
clase .fuente
{ "myObjectArray":[ {....} , {....} , {....} ] }
, he creado el archivo de modelo{....}
, ¿cómo obtengo este código genérico de colección para no asumir que mi elemento raíz es una matriz sin crear un nuevo archivo de objeto anidado?Otra forma es usar una matriz como tipo, por ejemplo:
De esta manera, evita 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:
En mi humilde opinión esto es mucho más legible.
Y para que sea una lista real (que se puede modificar, vea las limitaciones de
Arrays.asList()
), simplemente haga lo siguiente:fuente
MyClass
valor y se definirá dinámicamente!T[] yourClassList = gson.fromJson(message, T[].class);
// No se puede seleccionar a partir variable de tipomcList
en esta respuesta fue solo el resultado de la llamada aArrays.asList
. Este método devuelve una lista en la que la mayoría de los métodos opcionales, si no todos, se dejan sin implementar y arrojan excepciones. Por ejemplo, no puede agregar ningún elemento a esa lista. Como sugiere la edición posterior,Arrays.asList
tiene limitaciones, y envolverlo en un archivo real leArrayList
permite obtener una lista que es más útil en muchos casos.Array.newInstance(clazz, 0).getClass()
como se describe en la respuesta de David Wood .Consulte esta publicación. Java Type Generic como argumento para GSON
Tengo una mejor solución para esto. Aquí está la clase de contenedor para la lista para que el contenedor pueda almacenar exactamente el tipo de lista.
Y luego, el código puede ser simple:
fuente
mEntity.rulePattern
?Desde entonces
Gson 2.8
, podemos crear funciones de utilidad comoEjemplo usando
fuente
TypeToken#getParameterized
se ve mucho mejor que el truco con una subclase anónimaWep, otra forma de lograr el mismo resultado. Lo usamos por su legibilidad.
En lugar de hacer esta oración difícil de leer:
Cree una clase vacía que extienda una Lista de su objeto:
Y úsalo cuando analices el JSON:
fuente
Para Kotlin simplemente:
o, aquí hay una función útil:
Luego, para usar:
fuente
inline fun <reified T> buildType() = object : TypeToken<T>() {}.type!!
y llamarlo con el tipo de Lista:buildType<List<YourMagicObject>>()
buildType
y también llama a la función con el tipo genérico? ¿Es esto un error tipográfico? - Esto crearía ArrayList <ArrayList <YourMagicObject>>Ejemplo:
fuente
DevNG
la respuesta anterior, escrita 2 años antes: stackoverflow.com/a/17300003/1339923 (y lea esa respuesta para advertencias sobre este enfoque)Como responde a mi pregunta original, acepté la respuesta de doc_180, pero si alguien se encuentra con este problema nuevamente, 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 "sin argumentos", 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 la lista como lo sugiere el documento doc_180.
fuente
Aquí hay una solución que funciona con un tipo definido dinámicamente. El truco es crear el tipo adecuado de matriz usando Array.newInstance ().
fuente
class.cast()
evitar la advertencia no verificada causada por enviar a(T)
. O, mejor aún, no se moleste con la conversión y use algo comoArrays.asList()
convertir de una matriz a unaList<T>
. Además, no es necesario pasar una longitud aArray.newInstance()
: una matriz de tamaño cero será lo suficientemente buena como para llamargetClass()
.Quiero agregar para una posibilidad más. Si no desea utilizar TypeToken y desea convertir la matriz de objetos json en una ArrayList, puede proceder así:
Si su estructura json es como:
}
y tu estructura de clase es como:
entonces puedes analizarlo como:
Ahora puede acceder a cada elemento del objeto className.
fuente
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
Ejemplo 2
fuente
Me gustó la respuesta de kays1 pero no pude implementarla. Así que construí mi propia versión usando su concepto.
Uso:
fuente
En mi caso, la respuesta de @ uncaught_exceptions no funcionó, tuve que usar en
List.class
lugar dejava.lang.reflect.Type
:fuente