Jackson: desserialização de array de objetos em Java em 2025 — guia para profissionais

Treinador Online de Python para Iniciantes

Aprenda Python facilmente sem sobrecarga teórica. Resolva tarefas práticas com verificação automática e escreva código diretamente no navegador.

Start Course

Introdução: por que todo desenvolvedor Java deve conhecer este truque



Imagine: você recebeu um JSON do servidor, com dezenas de objetos do mesmo tipo. Clientes, produtos, logs — não importa. Você pega o ObjectMapper, escreve readValue(json, MyClass[].class) — e tudo funciona. Mas um mês depois o código falha com ClassCastException, porque alguém substituiu o array por um List. Familiar?



A pergunta «How to use Jackson to deserialise an array of objects» no Stack Overflow acumulou dezenas de milhares de visualizações. E não é por acaso: desserialização de array de objetos em Java é uma daquelas tarefas que parecem simples até você enfrentar genéricos e Type Erasure. Em 2025, Jackson continua sendo o padrão de facto para trabalhar com JSON, mas as melhores práticas mudaram. Neste artigo, abordaremos não apenas as abordagens básicas, mas também técnicas modernas que o livrarão de dores de cabeça.



Abordagem básica: array ou lista?



A maneira mais simples é usar um array. Jackson entende perfeitamente que MyClass[].class é um array de objetos:



ObjectMapper mapper = new ObjectMapper();String json = "[{\\"id\\":1,\\"name\\":\\"Alice\\"},{\\"id\\":2,\\"name\\":\\"Bob\\"}]";MyClass[] array = mapper.readValue(json, MyClass[].class);


Funciona? Sim. Mas esta abordagem tem desvantagens:

  • Array de tamanho fixo — inconveniente para dados dinâmicos.
  • Não possui métodos de coleções (stream(), filter(), remove()).
  • Mais difícil de expandir se posteriormente precisar de List.


Portanto, em 90% dos casos, você vai querer obter List<MyClass>. E é aqui que começa a parte interessante — Type Erasure em Java. Se você escrever:



List<MyClass> list = mapper.readValue(json, List.class); // warning: unchecked


O compilador reclamará e, em tempo de execução, você obterá um List<LinkedHashMap>, não um List<MyClass>. Os genéricos são apagados e o Jackson não sabe em que mapear os elementos.



TypeReference: a maneira correta para List



A solução é usar TypeReference. Esta é uma classe interna anônima que preserva a informação sobre os genéricos através de reflexão:



List<MyClass> list = mapper.readValue(json, new TypeReference<List<MyClass>>() {});


Observe o {} — isso cria uma classe anônima que captura o tipo. O Jackson, através de TypeFactory, entende que precisa desserializar um List de MyClass. Esta abordagem é o padrão ouro em 2025.



Quando o TypeReference é inconveniente?

  • Se você estiver formando o tipo dinamicamente (por exemplo, a partir de configuração).
  • Se precisar desserializar o mesmo tipo muitas vezes — criar uma classe anônima toda vez é um pouco custoso.


Para esses casos, existe uma alternativa — CollectionType.



CollectionType: o poder do JavaType



O Jackson fornece TypeFactory para construir tipos complexos:



JavaType type = mapper.getTypeFactory()    .constructCollectionType(List.class, MyClass.class);List<MyClass> list = mapper.readValue(json, type);


Este método:

  • Não cria classes anônimas (menos overhead).
  • Permite construir tipos dinamicamente: constructParametricType(Map.class, String.class, MyClass.class).
  • Ideal para bibliotecas e frameworks onde os tipos são desconhecidos em tempo de compilação.


Melhor prática de 2025: use TypeReference para casos simples, CollectionType quando precisar de flexibilidade ou desempenho.



Reader e InputStream: não se esqueça dos recursos



Blogs

Book Recommendations