Jackson é uma biblioteca popular para serializar/desserializar objetos Java em vários formatos de texto. A classe ObjectMapper é a principal forma da biblioteca trabalhar com o formato JSON. Para outros formatos, temos seus descendentes ( XmlMapper , YAMLMapper ). Graças à herança, podemos trabalhar com todos os formatos de forma consistente, através de uma única interface.

Baixar arquivos jar

Antes de estudar os exemplos, precisamos baixar os arquivos Jackson jar e conectá-los ao projeto no IntelliJ IDEA. Vamos pegar o exemplo de jackson-databind para ver como procurar os arquivos necessários:

  1. Acesse o site do Repositório Maven .

  2. Digite " jackson-databind " na caixa de pesquisa. Você obterá o seguinte:

  3. O primeiro resultado da pesquisa é o que nos interessa. Siga o link.

  4. Às vezes, uma versão específica de uma biblioteca pode ser necessária para garantir a compatibilidade com outros componentes de um projeto. A versão mais recente deve funcionar (no momento da redação desta lição, é 2.13.2.2). Siga o link.

  5. Na página que se abre, você deseja o link "pacote":

  6. Baixe o arquivo jar usando este link .

Seguindo um procedimento semelhante, você pode encontrar e baixar o restante dos arquivos jar necessários:

Após baixar todos os arquivos necessários, conecte-os ao projeto no IntelliJ IDEA:

  1. Abra as configurações do projeto (você pode fazer com a combinação de teclas Ctrl+Alt+Shift+S ).

  2. Vá para Bibliotecas .

  3. Pressione + e depois "Java". Selecione todos os arquivos baixados. Aqui está o que devemos terminar com:

  4. Isso conclui nosso trabalho preparatório. Agora podemos experimentar o ObjectMapper em ação.

Serialização para JSON

Primeiro, vamos serializar algum objeto para JSON:


import com.fasterxml.jackson.databind.ObjectMapper;
 
class Book {
	public String title;
	public String author;
	public int pages;
}
 
public class Solution {
	public static void main(String[] args) throws Exception {
    	Book book = new Book();
    	book.title = "Good Omens";
    	book.author = "Pratchett T., Gaiman N.";
    	book.pages = 383;
 
    	ObjectMapper mapper = new ObjectMapper();
    	String jsonBook = mapper.writeValueAsString(book);
    	System.out.println(jsonBook);
	}
}

A execução de main fornecerá esta saída:

{"title":"Good Omens","author":"Pratchett T., Gaiman N.","pages":383}

O ObjectMapper possui muitas configurações avançadas. Vamos usar um deles para tornar a string JSON mais legível. Depois de criar oObjectMapperobjeto, execute esta instrução:

mapper.enable(SerializationFeature.INDENT_OUTPUT);

As informações na saída permanecem as mesmas, mas agora há indentação e quebras de linha:

{
  "title" : "Good Omens",
  "autor" : "Pratchett T., Gaiman N.",
 "pages" : 383
}

Desserialização de JSON

Agora vamos fazer a ação oposta: vamos desserializar uma string em um objeto. Para poder ver o que o programa está fazendo, vamos sobrescrever o método toString na classe Book :


@Override
public String toString() {
	return "Book{" +
        	"title='" + title + '\'' +
        	", author='" + author + '\'' +
        	", pages=" + pages +
        	'}';
}

E faremos o seguinte no método main :


public static void main(String[] args) throws Exception {
	String jsonString = "{\"title\":\"Good Omens\",\"author\":\"Pratchett T., Gaiman N.\",\"pages\":383}";
	Book book = new ObjectMapper().readValue(jsonString, Book.class);
	System.out.println(book);
}

Saída:

Livro{title='Good Omens', author='Pratchett T., Gaiman N.', pages=383}

O método readValue está sobrecarregado — ele tem muitas variações que usam um arquivo, um link, vários fluxos de entrada, etc. Para simplificar, nosso exemplo usa uma variante que aceita uma string JSON.

Conforme mencionado acima, ObjectMapper tem muitas configurações. Vejamos alguns deles.

Ignorando propriedades desconhecidas

Considere uma situação em que uma string JSON tem uma propriedade que não existe na classe Book :


public static void main(String[] args) throws Exception {
	String jsonString = """
        	{
          	"title" : "Good Omens",
          	"author" : "Pratchett T., Gaiman N.",
          	"pages" : 383,
          	"unknown property" : 42
        	}""";
	ObjectMapper mapper = new ObjectMapper();
	Book book = mapper.readValue(jsonString, Book.class);
	System.out.println(book);
}

A execução desse código nos dá um UnrecognizedPropertyException . Este é o comportamento padrão, mas podemos alterá-lo:


ObjectMapper mapper =
new ObjectMapper().configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);

Ao criar umObjectMapperobjeto, usamos o método configure para definir a configuração correspondente como false . O método configure modifica o objeto que foi chamado e depois retorna esse mesmo objeto, então podemos fazer essa chamada de uma forma diferente:


ObjectMapper mapper = new ObjectMapper();
mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);

Em termos de funcionalidade, esta notação é igual à anterior.

Se agora executarmos o método main , a desserialização será bem-sucedida e a propriedade desconhecida será ignorada.

Anotações convenientes

Jackson nos fornece várias anotações que nos permitem personalizar o processo de serialização de várias maneiras. Vamos dar uma olhada em alguns dos mais úteis:

@JsonIgnore — Esta anotação é colocada acima de um elemento que deve ser ignorado durante a serialização/desserialização:


class Book {
	public String title;
	@JsonIgnore
	public String author;
	public int pages;
}

Aqui oautorcampo não será incluído no JSON resultante durante a serialização. Após a desserialização, oautorcampo receberá o valor padrão (nulo), mesmo que o JSON tenha um valor diferente.

@JsonFormat — Esta anotação permite definir o formato dos dados serializados. Vamos adicionar mais um campo, um Date , à classe Book :


class Book {
	public String title;
	public String author;
	public int pages;
	public Date createdDate = new Date();
}

Após a serialização, obtemos o seguinte JSON:

 {
  "title" : "Good Omens",
  "author" : "Pratchett T., Gaiman N.",
  "pages" : 383,
  "createdDate" : 1649330880788
}

Como você pode ver, a data foi serializada como um número. Adicionaremos uma anotação e definiremos o formato:


class Book {
	public String title;
	public String author;
	public int pages;
	@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd")
	public Date createdDate = new Date();
}

Agora o resultado da serialização é:

{
  "title" : "Good Omens",
  "author" : "Pratchett T., Gaiman N.",
  "pages" : 383,
  "createdDate" : "2022-04-07"
}

@JsonProperty — Esta anotação permite alterar o nome da propriedade que representa o campo serializado. Você também pode marcar métodos com esta anotação. Se você fizer isso, o valor de retorno será convertido em uma propriedade JSON durante a serialização:


class Book {
	@JsonProperty("name")
	public String title;
	public String author;
	public int pages;
 
	@JsonProperty("quotedTitle")
	public String getQuotedTitle() {
    	    return "\"" + title + "\"";
	}
}

Resultado da serialização:

{
  "autor" : "Pratchett T., Gaiman N.",
  "pages" : 383,
  "name" : "Good Omens",
  "quotedTitle" : "\"Good Omens\""
}

@JsonInclude — Usando esta anotação, você pode especificar as condições que devem ser satisfeitas para que um campo seja serializado. Você pode aplicá-lo a campos individuais ou a uma classe inteira. Primeiro, vamos tentar serializar um objeto com campos não inicializados:


public class Solution {
	public static void main(String[] args) throws Exception {
    		Book book = new Book();

    		ObjectMapper mapper = new ObjectMapper();
    		mapper.enable(SerializationFeature.INDENT_OUTPUT);
    		String jsonBook = mapper.writeValueAsString(book);
    		System.out.println(jsonBook);
	}
}

Resultado da serialização:

{
  "título": nulo,
  "autor": nulo,
  "páginas": 0
}

E se você adicionar a anotação:


@JsonInclude(JsonInclude.Include.NON_NULL)
class Book {
	public String title;
	public String author;
	public int pages;
}

Então obtemos este resultado:

{
  "páginas" : 0
}

Agora os campos nulos não são serializados.

@JsonPropertyOrder — Esta anotação permite definir a ordem na qual os campos são serializados:


@JsonPropertyOrder({"author", "title", "pages"})
class Book {
	public String title;
	public String author;
	public int pages;
}

Resultado da serialização:

{
  "autor" : "Pratchett T., Gaiman N.",
  "título" : "Boas Maldições",
  "páginas" : 383
}

Por enquanto, apenas lembre-se de como usar as anotações. No final deste módulo iremos conhecê-los melhor e até criar as nossas próprias anotações.

Serialização e desserialização em XML

Se precisarmos serializar em XML, podemos usar as mesmas configurações e anotações. A única diferença será a implementação doobjeto mapeador:


public static void main(String[] args) throws Exception {
	Book book = new Book();
	book.title = "Good Omens";
	book.author = "Pratchett T., Gaiman N.";
	book.pages = 383;
 
	ObjectMapper mapper = new XmlMapper();
	mapper.enable(SerializationFeature.INDENT_OUTPUT);
	String xmlBook = mapper.writeValueAsString(book);
	System.out.println(xmlBook);
}

Saída:

 <Book>
  <title>Good Omens</title>
  <author>Pratchett T., Gaiman N.</author>
  <pages>383</pages>
</Book>

Desserialização de XML:


public static void main(String[] args) throws Exception {
   String xmlString = """
            <Book>
             <title>Good Omens</title>
             <author>Pratchett T., Gaiman N.</author>
             <pages>383</pages>
           </Book>""";
   ObjectMapper mapper = new XmlMapper();
   Book book = mapper.readValue(xmlString, Book.class);
   System.out.println(book);
}

Serialização e desserialização em YAML

Lidamos com YAML da mesma forma que lidamos com XML:


public static void main(String[] args) throws Exception {
	Book book = new Book();
	book.title = "Good Omens";
	book.author = "Pratchett T., Gaiman N.";
	book.pages = 383;
 
	ObjectMapper mapper = new YAMLMapper();
	mapper.enable(SerializationFeature.INDENT_OUTPUT);
	String yamlBook = mapper.writeValueAsString(book);
	System.out.println(yamlBook);
}

Saída:

---
título: "Good Omens"
autor: "Pratchett T., Gaiman N."
páginas: 383

Desserialização de YAML:


public static void main(String[] args) throws Exception {
   String yamlString = """
           ---
           title: "Good Omens"
           author: "Pratchett T., Gaiman N."
           pages: 383""";
   ObjectMapper mapper = new YAMLMapper();
   Book book = mapper.readValue(yamlString, Book.class);
   System.out.println(book);
}