image

Acesse bootcamps ilimitados e +650 cursos

50
%OFF
Article image

GW

Guilherme Wallace27/02/2025 19:49
Compartilhe

Jackson vs Gson: A Pedra de Roseta da Serialização no Desenvolvimento Web com Java

    Em 1799, durante a campanha de Napoleão Bonaparte no Egito, um grupo de soldados franceses fez uma descoberta que mudaria para sempre o estudo da civilização egípcia: um bloco de granito negro, parcialmente quebrado, mas com um segredo poderoso. Gravado nele, havia um mesmo decreto escrito em três sistemas de escrita distintos - hieróglifo, demótico e grego antigo. Esse artefato, que ficaria conhecido como a Pedra de Roseta, tornou-se a chave para decifrar os mistérios do Egito Antigo, pois os estudiosos da época já compreendiam o grego e, a partir dele, conseguiram traduzir os hieróglifos, um enigma que havia permanecido indecifrável por séculos.

    Ao visitar o Museu Britânico e ver a Pedra de Roseta de perto, me impressionei com o impacto que esse objeto teve na história da linguagem. No fundo, a pedra representava a ponte entre três mundos - um intermediário que permitiu que línguas distintas se comunicassem.

    image

    Curiosamente, esse acontecimento me remeteu a um desafio semelhante no desenvolvimento web com Java. Aplicações modernas trocam informações constantemente, e um dos formatos mais comuns para isso é o JSON. Nesse ponto, para que um objeto Java possa ser compreendido por uma API, banco de dados, ou outros sistema, ele precisa ser convertido para JSON, e depois reconvertido (desserializado) de volta para um objeto Java. É aqui que entram Jackson e Gson - ferramentas que, assim como a Pedra de Roseta, permitem essa tradução entre diferentes linguagens, possibilitando a comunicação entre sistemas de maneira eficiente.

    Nesse artigo, exploraremos como Jackson e Gson desempenham esse papel, comparando suas vantagens e desvantagens para aplicações web. Assim como a Pedra de Roseta ajudou a decifrar um idioma perdido, essas bibliotecas nos ajudam a interpretar e manipular dados no desenvolvimento web com Java. Vamos explorar isso juntos.

    O que é serialização e desserialização?

    Java é uma linguagem fortemente orientada a objetos, onde os dados são representados por classes e objetos. No contexto de um sistema bancário, por exemplo, podemos ter uma classe que representa uma transação financeira, outra que armazena os dados de um cliente e assim por diante. Dentro do ambiente Java, esses objetos são facilmente compreendidos e manipulados.

    Porém, o problema surge quando precisamos compartilhar essas informações com outros sistemas, como uma API ou um banco de dados. Diferentes tecnologias podem ter diferentes formas de entender e armazenar dados.

    É aí que entra a serialização: um processo que converte objetos Java em um formato que pode ser facilmente armazenado ou transmitido, como JSON (JavaScript Object Notation) ou XML.

    Por outro lado, a desserialização faz o caminho inverso: transforma um JSON de volta em um objeto Java utilizável dentro da aplicação.

    Isso é essencial no desenvolvimento web, onde frequentemente precisamos trocar dados entre servidores e clientes de forma eficiente. E é exatamente aí que bibliotecas como Jackson e Gson entram em cena.

    image

    Jackson vs Gson: O embate das ferramentas

    Jackson e Gson destacam-se como duas das principais bibliotecas para serialização e desserialização de JSON em Java. A seguir, comparamos essas ferramentas em termos de casos de uso, velocidade, uso de memória e facilidade de uso.

    Casos de Uso:

    • Jackson: Ideal para aplicações que requerem alta performance e lidam com grandes volumes de dados, como sistemas corporativos de larga escala.
    • Gson: Recomendado para projetos mais simples ou de menor escala, onde a facilidade e rapidez de implementação são prioritárias.

    Velocidade de Serialização e Desserialização:

    • Jackson: Reconhecido por sua alta velocidade e otimização, especialmente em cenários que demandam alto desempenho.
    • Gson: Embora seja eficiente, pode apresentar desempenho inferior ao Jackson ao lidar com estruturas JSON mais complexas ou volumosas.

    Uso de Memória:

    • Jackson: Projetado para ser eficiente no uso de memória, sendo inclusive adequado para operações de streaming e manipulação de grandes volumes de dados JSON.
    • Gson: Funciona bem com dados de menor tamanho, mas pode consumir mais memória ao processar arquivos JSON maiores.

    Facilidade de Uso:

    • Jackson: Oferece uma ampla gama de funcionalidades e configurações avançadas, o que pode exigir um tempo maior de aprendizado para aproveitar todo o seu potencial.
    • Gson: Destaca-se pela simplicidade e facilidade de uso, permitindo uma integração rápida, especialmente útil em projetos com prazos apertados ou requisitos menos complexos.

    Jackson

    Para utilizar o Jackson em seus projetos, é necessário adicionar as dependências apropriadas. Abaixo, mostramos como fazer isso em projetos Maven e Gradle

    • Maven
    <dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>
    <version>2.18.2</version>
    </dependency>
    
    • Gradle
    dependencies {
    implementation 'com.fasterxml.jackson.core:jackson-databind:2.18.2'
    }
    

    Gson

    Paralelamente, para utilizar o Gson, esses são os comandos para adicionar tanto em projetos Maven como Gradle.

    • Maven
    <!-- https://mvnrepository.com/artifact/com.google.code.gson/gson -->
    <dependency>
    <groupId>com.google.code.gson</groupId>
    <artifactId>gson</artifactId>
    <version>2.12.1</version>
    </dependency>
    
    • Gradle
    dependencies {
     implementation 'com.google.code.gson:gson:2.12.1'
    }
    

    Serialização e Desserialização Simples

    Vamos definir uma classe Java que representará um Faraó do Egito Antigo, a qual será utilizada para conversão para JSON.

    image

    public class Farao {
      private String nome;
      private String dinastia;
      private String periodoDeReinado;
      private List<String> realizacoes;
    
    
      // Construtor
      public Farao(String nome, String dinastia, String periodoDeReinado, List<String> realizacoes) {
          this.nome = nome;
          this.dinastia = dinastia;
          this.periodoDeReinado = periodoDeReinado;
          this.realizacoes = realizacoes;
      }
    
    
      // Restante do Código ...
    }
    

    Tutancâmon decidiu utilizar Jackson

    Tutancâmon foi um faraó do Egito Antigo que governou entre c. 1332 a.C. e 1323 a.C., durante a XVIII Dinastia. Apesar de seu reinado curto, ele se tornou um dos faraós mais famosos da história devido à descoberta de seu túmulo praticamente intacto no século XX. Seu governo marcou a restauração dos antigos cultos religiosos, após as reformas monoteístas de seu predecessor, Akhenaton.

    Veja abaixo os exemplos com Jackson:

    • Serialização com Jackson: A seguir, criamos uma instância de Faraó e a transformamos em uma string JSON.
    import com.fasterxml.jackson.databind.ObjectMapper;
    
    public class JacksonSerializationExample {
    public static void main(String[] args) throws Exception {
      Farao tutancamon = new Farao(
          "Tutancâmon",
          "XVIII Dinastia",
          "c. 1 341 a.C. — c. 1 323 a.C.",
          new ArrayList<>()      
      );
    
      // Criar instância do ObjectMapper
      ObjectMapper objectMapper = new ObjectMapper();
    
      // Converter o objeto Faraó para JSON
      String jsonString = objectMapper.writeValueAsString(tutancamon);
    
      // Exibir o JSON resultante
      System.out.println(jsonString);
    }
    }
    

    Ao executar o método main vemos que ele imprimiu a JSON string correspondente ao objeto que criamos:

    {
      "nome": "Tutancâmon",
      "dinastia": "XVIII Dinastia",
      "periodoDeReinado": "c. 1 341 a.C. — c. 1 323 a.C.",
      "realizacoes": []
    }
    
    • Desserialização com Jackson: De outra forma, se em uma conexão web recebemos a resposta da API em JSON String, podemos transformá-la em objeto Faraó.

    Vamos partir do seguinte JSON representando um faraó do Egito, digamos que esse seja o retorno de uma requisição feita a uma API externa:

    {
    "nome": "Tutancâmon",
    "dinastia": "XVIII Dinastia",
    "periodoDeReinado": "c. 1 341 a.C - c. 1 323 a.C.",
    "realizacoes": []
    }
    

    Para converter esse JSON em um objeto da classe Farao, utilizamos o objectMapper do Jackson:

    import com.fasterxml.jackson.databind.ObjectMapper;
    import java.util.List;
    
    public class JacksonDeserializationExample {
    public static void main(String[] args) throws Exception {
      // JSON de exemplo
      String faraoJson = """
        {
          "nome": "Tutancâmon",
          "dinastia": "XVIII Dinastia",
          "periodoDeReinado": "c. 1 341 a.C. - c. 1 323 a.C.",
          "realizacoes": []
        }
      """;
    
      // Criar ObjectMapper
      ObjectMapper objectMapper = new ObjectMapper();
    
      // Desserializar JSON para objeto Java
      Farao tutancâmon = objectMapper.readValue(faraoJson, Farao.class);
    
      // Exibir resultado
      System.out.println("Nome: " + tutancamon.getNome());
      System.out.println("Dinastia: " + tutancamon.getDinastia());
      System.out.println("Período de Reinado: " + tutancamon.getPeriodoDeReinado());
      System.out.println("Realizações: " + tutancamon.getRealizacoes());
    }
    }
    
    
    

    A saída esperada ao rodar o código acima é:

    A saída esperada para o código acima é:
    Nome: Tutancâmon
    Dinastia: XVII 
    Período de Reinado: c. 1 341 a.C. - c. 1 323 a.C.
    Realizações: []
    

    Ramsés II optou por utilizar Gson

    Ramsés II, também conhecido como Ramsés, o Grande, foi um dos mais importantes e longevos faraós do Egito Antigo, governando entre 1279 a.C. e 1213 a.C. durante a XIX Dinastia. Ele é lembrado por suas grandiosas construções, como os templos de Abu Simbel, suas campanhas militares que expandiram o território egípcio e por assinar um dos primeiros tratados de paz registrados na história com os hititas.

    • Serialização com Gson: Façamos paralelamente a mesma operação feita com Jackson para comparação.
    import com.google.gson.Gson;
    import java.util.ArrayList;
    
    public class GsonSerializationExample {
    public static void main(String[] args) {
      // Criando um objeto Farao
      Farao ramses = new Farao(
        "Ramsés II",
        "XIX",
        "1279 a.C. – 1213 a.C.",
        new ArrayList<>()    
      );
    
      // Criando instância do Gson
      Gson gson = new Gson();
    
      // Convertendo o objeto para JSON
      String jsonString = gson.toJson(ramses);
    
      // Exibindo o JSON resultante
      System.out.println(jsonString);
    }
    }
    

    Aqui temos a saída esperada:

    {
    "nome": "Ramsés II",
    "dinastia": "XIX",
    "periodoDeReinado": "1279 a.C. - 1213 a.C.",
    "realizacoes": []
    }
    
    • Desserialização com Gson
    import com.google.gson.Gson;
    
    public class GsonDeserializationExample {
    public static void main(String[] args) {
      // JSON de exemplo representando um faraó
      String faraoJson = """
      {
        "nome": "Ramsés II",
        "dinastia": "XIX",
        "periodoDeReinado": "1279 a.C. – 1213 a.C.",
        "realizacoes": ["Expansão do Egito", "Construção de Abu Simbel"]
      }
      """;
    
      // Criando instância do Gson
      Gson gson = new Gson();
    
      // Desserializando JSON para objeto Java
      Farao ramses = gson.fromJson(faraoJson, Farao.class);
    
      // Exibindo os valores do objeto
      System.out.println("Nome: " + ramses.getNome());
      System.out.println("Dinastia: " + ramses.getDinastia());
      System.out.println("Período de Reinado: " + ramses.getPeriodoDeReinado());
      System.out.println("Realizações: " + ramses.getRealizacoes());
    }
    }
    

    E assim seria a saída esperada:

    Nome: Ramsés II
    Dinastia: XIX
    Período de Reinado: 1279 a.C. – 1213 a.C.
    Realizações: [Expansão do Egito, Construção de Abu Simbel]
    

    Tutancâmon vs Ramsés

    Agora que já entendemos como Jackson e Gson funcionam, vamos colocá-los à prova! Quem será mais rápido ao converter objetos Java para JSON e vice-versa?

    Para esse desafio, Tutancâmon representará o Jackson, enquanto Ramsés II usará Gson. Vamos medir o tempo necessário para serializar e desserializar 10.000 e em seguida 1.000.000 de objetos e descobrir quem leva a coroa da velocidade!

    Preparação do experimento

    Criaremos uma lista contendo faraós fictícios e mediremos o tempo de serialização e desserialização de cada biblioteca usando System.nanoTime(). A seguir, temos o código que utilizaremos:

    
    public class SerializacaoDesempenho {
      static int DEZ_MIL_FARAOS = 10000;
      static int UM_MILHAO_DE_FARAOS = 1000000;
    
      public static void main(String[] args) throws Exception {
          // Criando uma lista com faraós fictícios
          List<Farao> faraos = new ArrayList<>();
          for (int i = 0; i < DEZ_MIL_FARAOS; i++) {
              faraos.add(new Farao("Faraó " + i, "Dinastia " + (i % 20), "Ano " + (1300 - i) + " a.C.", new ArrayList<>()));
          }
    
          // Jackson - Serialização
          ObjectMapper objectMapper = new ObjectMapper();
          long inicioJacksonSerial = System.nanoTime();
          String jsonJackson = objectMapper.writeValueAsString(faraos);
          long fimJacksonSerial = System.nanoTime();
    
          // Jackson - Desserialização
          long inicioJacksonDeserial = System.nanoTime();
          List<Farao> listaJackson = objectMapper.readValue(jsonJackson, objectMapper.getTypeFactory().constructCollectionType(List.class, Farao.class));
          long fimJacksonDeserial = System.nanoTime();
    
          // Gson - Serialização
          Gson gson = new Gson();
          long inicioGsonSerial = System.nanoTime();
          String jsonGson = gson.toJson(faraos);
          long fimGsonSerial = System.nanoTime();
    
          // Gson - Desserialização
          long inicioGsonDeserial = System.nanoTime();
          List<Farao> listaGson = gson.fromJson(jsonGson, List.class);
          long fimGsonDeserial = System.nanoTime();
    
          // Exibir os resultados
          System.out.println("=== Resultado da Competição ===");
          System.out.println("Jackson - Tempo de Serialização: " + (fimJacksonSerial - inicioJacksonSerial) / 1_000_000.0 + " ms");
          System.out.println("Jackson - Tempo de Desserialização: " + (fimJacksonDeserial - inicioJacksonDeserial) / 1_000_000.0 + " ms");
          System.out.println("Gson - Tempo de Serialização: " + (fimGsonSerial - inicioGsonSerial) / 1_000_000.0 + " ms");
          System.out.println("Gson - Tempo de Desserialização: " + (fimGsonDeserial - inicioGsonDeserial) / 1_000_000.0 + " ms");
      }
    }
    

    Resultados

    • Para 10.000 faraós
    === Resultado da Competição ===
    Jackson - Tempo de Serialização: 227.382717 ms
    Jackson - Tempo de Desserialização: 169.068361 ms
    Gson - Tempo de Serialização: 117.46488 ms
    Gson - Tempo de Desserialização: 66.493696 ms
    

    Temos que o campeão foi o Ramses II representando a biblioteca Gson. Podemos ver que para o caso de JSON com esquemas simples e poucos dados temos a Gson com um ótimo desempenho.

    Agora para o caso de termos 1.000.000 de faraós fictícios em nossa lista, será que Gson ainda mantém a frente? Vejamos abaixo o resultado.

    • Para 1.000.000 de faraós
    === Resultado da Competição ===
    Jackson - Tempo de Serialização: 1242.482118 ms
    Jackson - Tempo de Desserialização: 1489.081513 ms
    Gson - Tempo de Serialização: 2467.687843 ms
    Gson - Tempo de Desserialização: 2169.338205 ms
    

    E jackson agora demonstra todo o seu poder para grandes volumes de dados com um ótimo desempenho e ganhando essa nova versão da competição.

    Conclusão

    Assim como a Pedra de Roseta foi essencial para decifrar os mistérios do Egito Antigo, Jackson e Gson desempenham um papel crucial na comunicação entre sistemas modernos. Ambos os frameworks se destacam na conversão de objetos Java para JSON e vice-versa, mas suas diferenças se tornam evidentes dependendo do cenário.

    Os testes mostraram que, para volumes menores de dados, Gson (representado por Ramsés II) leva vantagem em velocidade. No entanto, à medida que a carga aumenta, Jackson (nosso Tutancâmon) demonstra sua superioridade, lidando com grandes volumes de dados de forma mais eficiente. Isso reforça a ideia de que a escolha entre Jackson e Gson deve considerar não apenas a facilidade de uso, mas também os requisitos de desempenho do projeto.

    Se sua aplicação lida com grandes quantidades de dados e precisa de alto desempenho, Jackson é uma escolha robusta e otimizada. Já se a prioridade for simplicidade e rapidez em implementações menores, Gson pode ser a melhor opção. No fim, a decisão depende do contexto, assim como os faraós escolhiam suas estratégias para garantir a grandeza de seus impérios. 

    Compartilhe
    Recomendados para você
    Decola Tech 2025
    Microsoft AI for Tech - Copilot Studio
    Suzano - Python Developer
    Comentários (0)