Saltar al contenido

Obtenga un objeto JSON anidado con GSON usando la modificación

Ya no necesitas indagar más por todo internet ya que llegaste al lugar indicado, tenemos la respuesta que quieres hallar pero sin problemas.

Solución:

Escribiría un deserializador personalizado que devuelva el objeto incrustado.

Digamos que su JSON es:


    "status":"OK",
    "reason":"some reason",
    "content" : 
    
        "foo": 123,
        "bar": "some value"
    

Entonces tendrías un Content POJO:

class Content

    public int foo;
    public String bar;

Luego escribe un deserializador:

class MyDeserializer implements JsonDeserializer

    @Override
    public Content deserialize(JsonElement je, Type type, JsonDeserializationContext jdc)
        throws JsonParseException
    
        // Get the "content" element from the parsed JSON
        JsonElement content = je.getAsJsonObject().get("content");

        // Deserialize it. You use a new instance of Gson to avoid infinite recursion
        // to this deserializer
        return new Gson().fromJson(content, Content.class);

    

Ahora, si construyes un Gson con GsonBuilder y registre el deserializador:

Gson gson = 
    new GsonBuilder()
        .registerTypeAdapter(Content.class, new MyDeserializer())
        .create();

Puede deserializar su JSON directamente a su Content:

Content c = gson.fromJson(myJson, Content.class);

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:

class MyDeserializer implements JsonDeserializer

    @Override
    public T deserialize(JsonElement je, Type type, JsonDeserializationContext jdc)
        throws JsonParseException
    
        // Get the "content" element from the parsed JSON
        JsonElement content = je.getAsJsonObject().get("content");

        // Deserialize it. You use a new instance of Gson to avoid infinite recursion
        // to this deserializer
        return new Gson().fromJson(content, type);

    

Solo tienes que registrar una instancia para cada uno de tus tipos:

Gson gson = 
    new GsonBuilder()
        .registerTypeAdapter(Content.class, new MyDeserializer())
        .registerTypeAdapter(DiffContent.class, new MyDeserializer())
        .create();

Cuando usted llama .fromJson() el tipo se lleva al deserializador, por lo que debería funcionar para todos los tipos.

Y finalmente al crear una instancia de Retrofit:

Retrofit retrofit = new Retrofit.Builder()
                .baseUrl(url)
                .addConverterFactory(GsonConverterFactory.create(gson))
                .build();

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, ambos necesitan una TypeAdapter, debes registrar el TypeAdapter con el nueva instancia de GSON, de lo contrario el segundo TypeAdapter nunca será llamado. Esto se debe a que estamos creando una nueva Gson instancia dentro de nuestro deserializador personalizado.

Por ejemplo, si tuviera el siguiente JSON:


    "status": "OK",
    "reason": "some reason",
    "content": 
        "foo": 123,
        "bar": "some value",
        "subcontent": 
            "useless": "field",
            "data": 
                "baz": "values"
            
        
    

Y deseaba que este JSON se asignara a los siguientes objetos:

class MainContent

    public int foo;
    public String bar;
    public SubContent subcontent;


class SubContent

    public String baz;

Debería registrar el SubContent‘s TypeAdapter. Para ser más robusto, puede hacer lo siguiente:

public class MyDeserializer implements JsonDeserializer 
    private final Class mNestedClazz;
    private final Object mNestedDeserializer;

    public MyDeserializer(Class nestedClazz, Object nestedDeserializer) 
        mNestedClazz = nestedClazz;
        mNestedDeserializer = nestedDeserializer;
    

    @Override
    public T deserialize(JsonElement je, Type type, JsonDeserializationContext jdc) throws JsonParseException 
        // Get the "content" element from the parsed JSON
        JsonElement content = je.getAsJsonObject().get("content");

        // Deserialize it. You use a new instance of Gson to avoid infinite recursion
        // to this deserializer
        GsonBuilder builder = new GsonBuilder();
        if (mNestedClazz != null && mNestedDeserializer != null) 
            builder.registerTypeAdapter(mNestedClazz, mNestedDeserializer);
        
        return builder.create().fromJson(content, type);

    

y luego créalo así:

MyDeserializer myDeserializer = new MyDeserializer(SubContent.class,
                    new SubContentDeserializer());
Gson gson = new GsonBuilder().registerTypeAdapter(Content.class, myDeserializer).create();

Esto podría usarse fácilmente para el caso de “contenido” anidado, simplemente pasando una nueva instancia de MyDeserializer con null valores.

Un poco tarde, pero espero que esto ayude a alguien.

Simplemente cree el siguiente TypeAdapterFactory.

    public class ItemTypeAdapterFactory implements TypeAdapterFactory 

      public  TypeAdapter create(Gson gson, final TypeToken type) 

        final TypeAdapter delegate = gson.getDelegateAdapter(this, type);
        final TypeAdapter elementAdapter = gson.getAdapter(JsonElement.class);

        return new TypeAdapter() 

            public void write(JsonWriter out, T value) throws IOException 
                delegate.write(out, value);
            

            public T read(JsonReader in) throws IOException 

                JsonElement jsonElement = elementAdapter.read(in);
                if (jsonElement.isJsonObject()) 
                    JsonObject jsonObject = jsonElement.getAsJsonObject();
                    if (jsonObject.has("content")) 
                        jsonElement = jsonObject.get("content");
                    
                

                return delegate.fromJsonTree(jsonElement);
            
        .nullSafe();
    

y agréguelo a su constructor GSON:

.registerTypeAdapterFactory(new ItemTypeAdapterFactory());

o

 yourGsonBuilder.registerTypeAdapterFactory(new ItemTypeAdapterFactory());

Acuérdate de que puedes permitirte aclarar si topaste tu impedimento .

¡Haz clic para puntuar esta entrada!
(Votos: 0 Promedio: 0)



Utiliza Nuestro Buscador

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *