How to transoform JSON into an array of objects of a specific class, and does this class have compound attributes?

3

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

I have the following situation: I have a Response class that has some attributes, among them a list of " Post ", an object of class " Post " has a list of objects of class Anexo "and I need to generate this list correctly, which I can not do.

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

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

I have the following json to fill this list of posts

[
  {
    "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 enough, Thanks.

    
asked by anonymous 17.05.2015 / 05:09

1 answer

1

Starting from the JSON presenting for 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 will not work.

In the first case an error will appear: Expected BEGIN_OBJECT but was BEGIN_ARRAY , because, of course JSON does not start with an object but a vector; in the second, all the 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 is some way to do this and I will only show one.

  • use @SerializedName for non-default name attributes supported;
  • create a custom deserializer. Here's how it works: writing a deserializer ;
  • use FieldNamingStrategy and define the naming strategy used in its attributes, a DE-PARA between attributes in java objects and those in JSON;
  • rename the attributes of your objects to reflect some standard approach already supported by Gson. See this link: FieldNamingPolicy ;
  • As you have not mentioned which approach you are already using to deserialize up the list and Post s, I will show the third approach as an example by creating a naming strategy of your own.

    I'm only considering the attributes shown in the question, if there are others that do not follow the pattern you should consider in your implementation.

    In order to have this strategy of its own we will implement the FieldNamingStrategy , the method implementation #translate(Field) 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 does not 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 they are in lower case separated by a _ of the attribute name.

    You can implement the 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 this way (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();
        }
    };
    

    After implementing the nomenclature strategy, we can use it this way:

    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 , it's up to you.

        
    17.05.2015 / 16:25