java – How to transform JSON into an array of objects of a specific class, given that this class has composite attributes?

Question:

I encountered the following problem when trying to transform a JSON String into an object list.

I have the following situation: I have a Response class that has some attributes, including a list of " Post ", and an object of class " Post " has a list of objects of class " Anexo " and I need to generate this list correctly , which I'm not getting.

NOTE: using Gson, the other attributes, which are String s, were filled in correctly, but when I got to this list I had problems. In fact, I think Gson did it, but I can't see the structure.

class Response {
    private List<Post> mPosts;
    // Outros atributos e métodos.
}

I have the following json to fill this post list

[
  {
    "post_id": "1",
    "post_descricao": "Meu post 1",
    "post_titulo": "Teste",
    "anexos": [
      {
        "anexo_id": "3",
        "anexo_uri": "img-03.png"
      },
      {
        "anexo_id": "4",
        "anexo_uri": "img-04.png"
      }
    ]
  },
  {
    "post_id": "3",
    "post_descricao": "Meu post 2",
    "post_titulo": "Teste 2",
    " anexos": [
      {
        "anexo_id": "1",
        "anexo_uri": "img-01.png"
      },
      {
        "anexo_id": "2",
        "anexo_uri": "img-02.png"
      }
    ]
  }
]

And I have the posts and attachments classes:

class Post {
    private int id;
    private String titulo;
    private String descricao;
    private List<Anexo> mAnexos;

    // Outros códigos.
}
class Anexo {
    private int id;
    private String uri;

    // Outros códigos.
}

How to do it correctly? I've tried a lot, thanks.

Answer:

Starting from the JSON presented by you and the data structure also presented in the question, if we use a standard approach like this:

final Gson gson = new Gson();
final Response response = gson.fromJson(json, Response.class);

Or this:

final Gson gson = new Gson();
final Type type = new TypeToken<List<Post>>() {}.getType();
final List<Post> posts = gson.fromJson(json, type);
response.setMPosts(posts);

It won't work.

In the first case, an error will be displayed: Expected BEGIN_OBJECT but was BEGIN_ARRAY , because obviously the JSON does not start with an object, but a vector; in the second, all attributes will be null or with their default value, this is because Gson does not support by default the naming policy adopted in these objects.

There are a few ways to do this and I'll just show you one.

  1. use @SerializedName on supported non-standard name attributes;
  2. create a custom deserializer. Here's how it works: writing a deserializer ;
  3. use FieldNamingStrategy and define the naming strategy used in its attributes, a DE-PARA between attributes in java objects and those in JSON;
  4. rename the attributes of your objects to reflect some standard approach already supported by Gson. See this link: FieldNamingPolicy ;

As you haven't mentioned which approach you are already using to deserialize to the list and Post s, I'll show you as an example the third approach, creating your own naming strategy.

I'm only considering the attributes shown in the question, if there are others that don't follow the pattern you should consider their implementation.

To have this own strategy, we will implement the FieldNamingStrategy interface, the implementation of the #translate(Field) method will look something like this:

final String fieldName = f.getName();
if (fieldName.equalsIgnoreCase("mAnexos")) {
    return "anexos";
}

final Class<?> declaringClass = f.getDeclaringClass();
final String className = declaringClass.getSimpleName().toLowerCase();

return className + "_" + fieldName.toLowerCase();

The mAnexos attribute is the only one that doesn't share the same pattern as the other attributes, so if it is we will return attachments , the name of the attribute in JSON . The others follow the same pattern, that is, the name of the class in which they are in lower case separated by a _ from the attribute name.

You can implement strategy in several ways, an example in Java 8 would be this:

final FieldNamingStrategy strategy = (final Field f) -> {
    final String fieldName = f.getName();
    if (fieldName.equalsIgnoreCase("mAnexos")) {
        return "anexos";
    }

    final Class<?> declaringClass = f.getDeclaringClass();
    final String className = declaringClass.getSimpleName().toLowerCase();

    return className + "_" + fieldName.toLowerCase();
};

In other versions of Java you can implement it like this (with anonymous class):

final FieldNamingStrategy strategy = new FieldNamingStrategy() {
    public String translateName(final Field f) {
        final String fieldName = f.getName();
        if (fieldName.equalsIgnoreCase("mAnexos")) {
            return "anexos";
        }

        final Class<?> declaringClass = f.getDeclaringClass();
        final String className = declaringClass.getSimpleName().toLowerCase();

        return className + "_" + fieldName.toLowerCase();
    }
};

Once we've implemented the naming strategy, we can use it like this:

final Gson gson = new GsonBuilder().setFieldNamingStrategy(strategy).create();

final Type type = new TypeToken<List<Post>>() {}.getType();

final List<Post> posts = gson.fromJson(json, type); // substitua "json" pelo o json que você precisa deserializar
final Response response = new Response();
response.setMPosts(posts);

You can also create another object that implements FieldNamingStrategy , at your discretion.

Scroll to Top
AllEscort