使用Gson使用List反序列化对象

时间:2018-05-16 00:52:03

标签: java json list gson

我正在尝试反序列化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'}

使用Gson的简单方法

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

但是,当我分析我的对象时,联系人列表和公司时间表是空的。 Object after deserialization

使用的类如下:

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 [..] }

我已经用过它了

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

但由于我没有使用登录列表,因此我没有从第一种方法中获得任何差异化效果。

注意:正确设置了列表中没有的所有其他数据。

1 个答案:

答案 0 :(得分:1)

如果您只是减少要反序列化的代码量和JSON文档的大小,那就太好了。

Gson在没有默认构造函数的类中使用其UnsafeAllocatorsun.misc.Unsafe.allocateInstance(至少对于我的JVM实例)。 这不需要分配对象而不调用它们的构造函数,因为Gson无法正确构造内部类:您正在使用具有隐式编译器生成的构造函数的内部类来引用它的外部类引用。 例如,具有以下类

class Login {

    Empresa empresa;

    class Empresa {

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

        class Contato {

            int idContato;
            String contato;
            String tipoContato;

        }

    }

}

调用Login.Empresa.class.getDeclaredConstructors()将生成唯一的编译器生成的构造函数:q50361018.Login$Empresa(q50361018.Login)。 我真的不记得了,但初始化器似乎在构造函数体之前被调用(并且可能是构造函数体的一部分)。 这意味着

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

将返回contato始终设置为null,因为没有调用构造函数并且没有调用字段初始值设定项。 但是,在反序列化期间可以设置contato字段。 至少如果您将其名称修改为listaContato或使用@SerializedName('listaContato')注释该字段。 所以,解决方案只是:

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;

        }

    }

}

甚至更好,避免为数据传输目的服务的内部类(如果可能,我个人会不惜一切代价避免使用它们):

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;

}

以上所有三个类都假设它们是包级别的类。

演示:

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));
}

输出:

0 234234 Celular
0 323423 Celular
0 234234234 Celular