Reinaldet
Reinaldet

Reputation: 13

Deserialize Object with List using Gson

I'm trying to deserialize a Json

{'empresa':{'areaAtuacao':{'areaAtuacao':'Primeiro','idAreaAtuacao':0},
'cnpjEmpresa':'561561','empresaAtivada':false,
'endereco':{'bairro':'Jardim Europa','cep':'85859318','cidade':'Foz do Iguaçu','complemento':'','estado':'PR','idEndereco':0,'logradouro':'Rua França','numero':'71'},
'idEmpresa':0,
'listaContato':[{'contato':'234234','idContato':0,'tipoContato':'Celular'},
    {'contato':'323423','idContato':0,'tipoContato':'Celular'},
    {'contato':'234234234','idContato':0,'tipoContato':'Celular'},
    {'contato':'324','idContato':0,'tipoContato':'Celular'},
    {'contato':'324','idContato':0,'tipoContato':'Celular'},
    {'contato':'3','idContato':0,'tipoContato':'Celular'},
    {'contato':'432','idContato':0,'tipoContato':'Celular'},
    {'contato':'432','idContato':0,'tipoContato':'Celular'},
    {'contato':'4','idContato':0,'tipoContato':'Celular'},
    {'contato':'23','idContato':0,'tipoContato':'Celular'},
    {'contato':'4234','idContato':0,'tipoContato':'Celular'},
    {'contato':'34','idContato':0,'tipoContato':'Celular'}],
'listaHorario':
    [{'diaSemana':{'diaSemana':'Segunda-Feira','idDiaSemana':0},'fimExpediente':{'year':2018,'month':4,'dayOfMonth':15,'hourOfDay':20,'minute':16,'second':58},'fimIntervalo':{'year':2018      ,'month':4,'dayOfMonth':15,'hourOfDay':20,'minute':16,'second':58},'idHorarioEmpresa':0,'inicioExpediente':{'year':2018,'month':4,'dayOfMonth':15,'hourOfDay':20,'minute':16,'second':58},'inicioIntervalo':{'year':2018,'month':4,'dayOfMonth':15,'hourOfDay':20,'minute':16,'second':58}},
    {'diaSemana':{'diaSemana':'Terça-Feira','idDiaSemana':0},'fimExpediente':{'year':2018,'month':4,'dayOfMonth':15,'hourOfDay':20,'minute':16,'second':58},'fimIntervalo':{'year':2018,'month':4,'dayOfMonth':15,'hourOfDay':20,'minute':16,'second':58},'idHorarioEmpresa':0,'inicioExpediente':{'year':2018,'month':4,'dayOfMonth':15,'hourOfDay':20,'minute':16,'second':58},'inicioIntervalo':{'year':2018,'month':4,'dayOfMonth':15,'hourOfDay':20,'minute':16,'second':58}},
    {'diaSemana':{'diaSemana':'Quarta-Feira','idDiaSemana':0},'fimExpediente':{'year':2018,'month':4,'dayOfMonth':15,'hourOfDay':20,'minute':16,'second':58},'fimIntervalo':{'year':2018,'month':4,'dayOfMonth':15,'hourOfDay':20,'minute':16,'second':58},'idHorarioEmpresa':0,'inicioExpediente':{'year':2018,'month':4,'dayOfMonth':15,'hourOfDay':20,'minute':16,'second':58},'inicioIntervalo':{'year':2018,'month':4,'dayOfMonth':15,'hourOfDay':20,'minute':16,'second':58}},
    {'diaSemana':{'diaSemana':'Quinta-Feira','idDiaSemana':0},'fimExpediente':{'year':2018,'month':4,'dayOfMonth':15,'hourOfDay':20,'minute':16,'second':58},'fimIntervalo':{'year':2018,'month':4,'dayOfMonth':15,'hourOfDay':20,'minute':16,'second':58},'idHorarioEmpresa':0,'inicioExpediente':{'year':2018,'month':4,'dayOfMonth':15,'hourOfDay':20,'minute':16,'second':58},'inicioIntervalo':{'year':2018,'month':4,'dayOfMonth':15,'hourOfDay':20,'minute':16,'second':58}},
    {'diaSemana':{'diaSemana':'Sexta-Feira','idDiaSemana':0},'fimExpediente':{'year':2018,'month':4,'dayOfMonth':15,'hourOfDay':20,'minute':16,'second':58},'fimIntervalo':{'year':2018,'month':4,'dayOfMonth':15,'hourOfDay':20,'minute':16,'second':58},'idHorarioEmpresa':0,'inicioExpediente':{'year':2018,'month':4,'dayOfMonth':15,'hourOfDay':20,'minute':16,'second':58},'inicioIntervalo':{'year':2018,'month':4,'dayOfMonth':15,'hourOfDay':20,'minute':16,'second':58}},{'diaSemana':
    {'diaSemana':'Sábado','idDiaSemana':0},'fimExpediente':{'year':2018,'month':4,'dayOfMonth':15,'hourOfDay':20,'minute':16,'second':58},'fimIntervalo':{'year':2018,'month':4,'dayOfMonth':15,'hourOfDay':20,'minute':16,'second':58},'idHorarioEmpresa':0,'inicioExpediente':{'year':2018,'month':4,'dayOfMonth':15,'hourOfDay':20,'minute':16,'second':58},'inicioIntervalo':{'year':2018,'month':4,'dayOfMonth':15,'hourOfDay':20,'minute':16,'second':58}},
    {'diaSemana':{'diaSemana':'Domingo','idDiaSemana':0},'fimExpediente':{'year':2018,'month':4,'dayOfMonth':15,'hourOfDay':20,'minute':16,'second':58},'fimIntervalo':{'year':2018,'month':4,'dayOfMonth':15,'hourOfDay':20,'minute':16,'second':58},'idHorarioEmpresa':0,'inicioExpediente':{'year':2018,'month':4,'dayOfMonth':15,'hourOfDay':20,'minute':16,'second':58},'inicioIntervalo':{'year':2018,'month':4,'dayOfMonth':15,'hourOfDay':20,'minute':16,'second':58}}],
'logoEmpresa':[-1,-40,-1,-32,0,16,74,70,73,70,0,1,1,0,0,1,0,1,0,0,-1,-31,33,65,69,120,105,102,0,0,73,73,42,0,8,0,0,0,9,0,15,1,2,0,18,0,0,0,-98,0,0,0,16,1,2,0,18,0,0,0,-80,0,0,0,18,1,4,0,1,0,0,0,1,0,0,0,26,1,5,0,1,0,0,0,122,0,0,0,27,1,5,0,1,0,0,0,-126,0,0,0,40,1,3,0,1,0,0,0,2,0,0,0,50,1,2,0,20,0,0,0,-118,0,0,0,19,2,3,0,1,0,0,0,1,0,0,0,105,-121,4,0,1,0,0,0,-62,0,0,0,36,1,0,0,72,0,0,0,1,0,0,0,72,0,0,0,1,0,0,0,50,48,49,56,58,48,53,58,49,53,32,50,48,58,49,54,58,49,57,0,69,109,117,108,97,116,111,114,45,71,111,108,100,102,105,115,104,0,69,109,117,108,97,116,111,114,45,71,111,108,100,102,105,115,104,0,7,0,0,-112,7,0,4,0,0,0,48,50,49,48,1,-111,7,0,4,0,0,0,1,2,3,0,10,-110,5,0,1,0,0,0,28,1,0,0,0,-96,7,0,4,0,0,0,48,49,48,48,1,-96,3,0,1,0,0,0,-1,-1,0,0,2,-96,4,0,1,0,0,0,-128,2,0,0,3,-96,4,0,1,0,0,0,-32,1,0,0,0,0,0,0,36,19,0,0,-24,3,0,0,2,0,1,2,4,0,1,0,0,0,66,1,0,0,2,2,4,0,1,0,0,0,-9,31,0,0,0,0,0,0,-1,-40,-1,-32,0,16,74,70,73,70,0,1,1,0,0,1,0,1,0,0,-1,-37,0,67,0,5,3,4,4,4,3,5,4,4,4,5,5,5,6,7,12,8,7,7,7,7,15,11,11,9,12,17,15,18,18,17,15,17,17,19,22,28,23,19,20,26,21,17,17,24,33,24,26,29,29,31,31,31,19,23,34,36,34,30,36,28,30,31,30,-1,-37,0,67,1,5,5,5,7,6,7,14,8,8,14,30,20,17,20],
'nomeFantasia':'jsdnjkfndkjn','publicoAlvo':'Unissex'},'encontrado':false,'idLogin':0,'senha':'B17EF6D19C7A5B1EE83B907C595526DCB1EB06DB8227D650D5DDA0A9F4CE8CD9','usuario':'51456'}

Using Gson's simple method

    Login dadosEmpresa = new Gson().fromJson(dados, Login.class);

However, when I analyze my object, Contact List and Company Schedule are empty. Object after deserialization

The classes used are as follows:

public class Login {

    private int idLogin;
    private String usuario;
    private String senha;
    private String loginGoogle;
    private Cliente cliente;
    private Empresa empresa;

    [...] Gets e Sets [..] }

       public class Empresa {

            private int idEmpresa;
            private String nomeFantasia;
            private String cnpjEmpresa;
            private String descricaoEmpresa;
            private byte[] logoEmpresa;
            private boolean empresaAtivada;
            private Calendar desativadaEm;
            private String genero;
            AreaAtuacao areaAtuacao = new  AreaAtuacao();
            Endereco endereco = new Endereco();
            List<HorarioEmpresa> horarioEmpresa = new ArrayList<>();
            List<Contato> contato = new ArrayList<>();
            List<ServicoPrestado> servicoPrestado = new ArrayList<>();

    [...] Gets e Sets [..] }

    public class Contato {

        private int idContato;
        private String contato;
        private String tipoContato;


    [...] Gets e Sets [..] }


    public class HorarioEmpresa {

        private int idHorarioEmpresa;
        private Calendar inicioExpediente;
        private Calendar inicioIntervalo;
        private Calendar fimIntervalo;
        private Calendar fimExpediente;
        private DiaSemana diaSemana;

    [...] Gets e Sets [..] }

I already used it

Type dados = new TypeToken<Login>() {}.getType();

But since I'm not working with a Login list, I did not get any differentiated effect from the first method.

Note: All other data that is not in the List is being set correctly.

Upvotes: 1

Views: 91

Answers (1)

Lyubomyr Shaydariv
Lyubomyr Shaydariv

Reputation: 21105

It would be nice if you'd simply reduce the amount of code and the size of the JSON document you are going to deserialize.

Gson uses its UnsafeAllocator and sun.misc.Unsafe.allocateInstance under the hood (at least for my JVM instance) for classes that do not have default constructors. This is required no allocate objects without their constructors being invoked, because Gson cannot construct inner classes properly: you're using inner classes that have an implicit compiler-generated constructor to reference its outer class reference. For example, having the following classes

class Login {

    Empresa empresa;

    class Empresa {

        List<Contato> contato = new ArrayList<>();

        class Contato {

            int idContato;
            String contato;
            String tipoContato;

        }

    }

}

invoking Login.Empresa.class.getDeclaredConstructors() will produce the only compiler-generated constructor: q50361018.Login$Empresa(q50361018.Login). I don't really remember, but initializers seem to be invoked right before constructor bodies (and probably are a part of constructor bodies). This means that

final UnsafeAllocator unsafeAllocator = UnsafeAllocator.create();
System.out.println(unsafeAllocator.newInstance(Login.Empresa.class).contato);

will return contato always set to null because no constructor was invoked and no field initializers are invoked. However, the contato field can be set during deserialization. At least if you fix its name to listaContato or annotate the field with @SerializedName('listaContato'). So, the solution is just:

class Login {

    Empresa empresa;

    class Empresa {

        // This is the solution 
        List<Contato> listaContato = new ArrayList<>();
        // Or the following
        // @SerializedName("listaContato")
        // List<Contato> contato = new ArrayList<>();
        // None of the solutions can fix the default empty array list though

        class Contato {

            int idContato;
            String contato;
            String tipoContato;

        }

    }

}

Or even better, avoid inner classes that serve data-transfer purposes (I personally avoid them at all costs if possible):

class Login {

    Empresa empresa;

}


class Empresa {

    // This will always be an empty array list even if there is `listaContato` in the JSON document
    List<Contato> listaContato = new ArrayList<>();

}

class Contato {

    int idContato;
    String contato;
    String tipoContato;

}

All three classes above assume that they are package-level classes.

Demo:

try ( final JsonReader jsonReader = Resources.getPackageResourceJsonReader(Q50361018.class, "whatever.json") ) {
    final Login login = gson.fromJson(jsonReader, Login.class);
    login.empresa.listaContato
            .stream()
            .limit(2)
            .forEach(contato -> System.out.println(contato.idContato + " " + contato.contato + " " + contato.tipoContato));
}

Output:

0 234234 Celular
0 323423 Celular
0 234234234 Celular

Upvotes: 1

Related Questions