Estoy consumiendo una API de mi aplicación de Android, y todas las respuestas JSON son así:
{
'status': 'OK',
'reason': 'Everything was fine',
'content': {
< some data here >
}
El problema es que todos mis POJO status
, reason
campos, y dentro del content
campo es el POJO real Quiero.
¿Hay alguna forma de crear un convertidor personalizado de Gson para extraer siempre el content
campo, por lo que la actualización devuelve el POJO apropiado?
Respuestas:
Escribiría un deserializador personalizado que devuelva el objeto incrustado.
Digamos que su JSON es:
Entonces tendrías un
Content
POJO:Luego escribe un deserializador:
Ahora, si construye un
Gson
conGsonBuilder
y registra el deserializador:Puede deserializar su JSON directamente a su
Content
:Editar para agregar desde los comentarios:
Si tiene diferentes tipos de mensajes pero todos tienen el campo "contenido", puede hacer que Deserializer sea genérico haciendo lo siguiente:
Solo tienes que registrar una instancia para cada uno de tus tipos:
Cuando llamas,
.fromJson()
el tipo se lleva al deserializador, por lo que debería funcionar para todos tus tipos.Y finalmente al crear una instancia de Retrofit:
fuente
setConverter(new GsonConverter(gson))
en laRestAdapter.Builder
clase de RetrofitPerson.class
yList<Person>.class
/Person[].class
con Deserializer separado?La solución de @ BrianRoach es la solución correcta. Vale la pena señalar que en el caso especial en el que ha anidado objetos personalizados que necesitan un personalizado
TypeAdapter
, debe registrar elTypeAdapter
con la nueva instancia de GSON ; de lo contrarioTypeAdapter
, nunca se llamará al segundo . Esto se debe a que estamos creando una nuevaGson
instancia dentro de nuestro deserializador personalizado.Por ejemplo, si tuviera el siguiente JSON:
Y deseaba que este JSON se asignara a los siguientes objetos:
Usted tendría que registrar los
SubContent
'sTypeAdapter
. Para ser más robusto, puede hacer lo siguiente:y luego créalo así:
Esto también podría usarse fácilmente para el caso de "contenido" anidado simplemente pasando una nueva instancia de
MyDeserializer
con valores nulos.fuente
java.lang.reflect.Type
Un poco tarde, pero espero que esto ayude a alguien.
Simplemente cree el siguiente TypeAdapterFactory.
y agréguelo a su constructor GSON:
o
fuente
jsonElement
?. como tengocontent
,content1
, etc.Tuve el mismo problema hace un par de días. Resolví esto usando la clase contenedora de respuesta y el transformador RxJava, que creo que es una solución bastante flexible:
Envoltura:
Excepción personalizada para lanzar, cuando el estado no es correcto:
Transformador Rx:
Uso de ejemplo:
Mi tema: Retrofit 2 RxJava - Gson - Deserialización "global", cambio de tipo de respuesta
fuente
Continuando con la idea de Brian, dado que casi siempre tenemos muchos recursos REST cada uno con su propia raíz, podría ser útil generalizar la deserialización:
Luego, para analizar la carga útil de muestra de arriba, podemos registrar el deserializador GSON:
fuente
Una mejor solución podría ser esta ...
Luego, defina su servicio así ...
fuente
Según la respuesta de @Brian Roach y @rafakob, hice esto de la siguiente manera
Respuesta json del servidor
Clase de manejador de datos común
Serializador personalizado
Objeto gson
Llamada de API
fuente
Esta es la misma solución que @AYarulin pero suponga que el nombre de la clase es el nombre de la clave JSON. De esta manera solo necesita pasar el nombre de la clase.
Luego, para analizar la carga útil de muestra de arriba, podemos registrar el deserializador GSON. Esto es problemático ya que la clave distingue entre mayúsculas y minúsculas, por lo que el nombre de la clase debe coincidir con el caso de la clave JSON.
fuente
Aquí hay una versión de Kotlin basada en las respuestas de Brian Roach y AYarulin.
fuente
En mi caso, la clave "contenido" cambiaría para cada respuesta. Ejemplo:
En tales casos, utilicé una solución similar a la enumerada anteriormente, pero tuve que modificarla. Puedes ver la esencia aquí . Es demasiado grande para publicarlo aquí en SOF.
Se
@InnerKey("content")
usa la anotación y el resto del código es para facilitar su uso con Gson.fuente
No se olvide
@SerializedName
y@Expose
anotaciones para todos los miembros de la clase y los miembros de la clase interna que la mayoría de deserializado JSON por GSON.Mire https://stackoverflow.com/a/40239512/1676736
fuente
Otra solución simple:
fuente