Mapeamento de Objetos com a Biblioteca Jackson

JavaBeginner
Pratique Agora

Introdução

Neste laboratório, aprenderemos como usar a classe ObjectMapper do Jackson para mapear objetos para JSON e JSON para objetos. Usaremos uma classe Java simples chamada DemoClass e aprenderemos várias técnicas para ler e escrever dados JSON.

Criar e Compilar DemoClass

Crie um novo projeto no diretório ~/project e crie uma nova classe Java DemoClass. Cole o seguinte código no arquivo de código DemoClass.java.

import java.util.Date;

public class DemoClass {
    private String field1;
    private Double field2;
    private Date dateField;

    // Constructors
    DemoClass() {}

    DemoClass(String field1, Double field2, Date dateField) {
        this.field1 = field1;
        this.field2 = field2;
        this.dateField = dateField;
    }

    // getters and setters
    public String getField1() {
        return field1;
    }

    public void setField1(String field1) {
        this.field1 = field1;
    }

    public Double getField2() {
        return field2;
    }

    public void setField2(Double field2) {
        this.field2 = field2;
    }

    public Date getDateField() {
        return dateField;
    }

    public void setDateField(Date dateField) {
        this.dateField = dateField;
    }
}

Compile a classe Java DemoClass usando o seguinte comando:

javac DemoClass.java

Lendo Objetos de um Arquivo JSON

Podemos usar o método readValue() da classe ObjectMapper para ler dados de um arquivo JSON em um objeto. Nosso arquivo JSON contém apenas pares de propriedade-valor de um único objeto.

Crie um novo arquivo chamado demo.json e cole o seguinte conteúdo JSON nele.

{
    "field1": "Sample-1",
    "field2": 20.21,
    "dateField": "2021-07-30T14:20:30.000Z"
}

Use o seguinte código para ler o arquivo JSON e mapeá-lo para um objeto DemoClass.

import java.io.File;
import java.text.SimpleDateFormat;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;

public class ObjectMapperDemo {
    public static void main(String[] args) {
        try {
            String filePath = "demo.json";
            File file = new File(filePath);

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

            DemoClass obj = objMapper.readValue(file, DemoClass.class);

            System.out.println("Field1: " + obj.getField1());
            System.out.println("Field2: " + obj.getField2());
            System.out.println("DateField: " + obj.getDateField());
        } catch (Exception e) {
            System.out.println(e);
        }
    }
}

A saída será:

Field1: Sample-1
Field2: 20.21
DateField: Fri Jul 30 14:20:30 UTC 2021

Lendo Objetos de uma String JSON

Podemos ler dados de uma string JSON em um objeto. Usaremos o método readValue() da classe ObjectMapper. Também precisamos passar o tipo da classe para este método.

Adicione o seguinte código para ler dados de uma string JSON.

String jsonString = "{\"field1\":\"Sample-1\",\"field2\":20.21,\"dateField\":\"2021-07-30T14:20:30.000Z\"}";

ObjectMapper objMapper = new ObjectMapper();
DemoClass obj = objMapper.readValue(jsonString, DemoClass.class);

System.out.println("Field1: " + obj.getField1());
System.out.println("Field2: " + obj.getField2());
System.out.println("DateField: " + obj.getDateField());

A saída será:

Field1: Sample-1
Field2: 20.21
DateField: Fri Jul 30 14:20:30 UTC 2021

Lendo Objetos de uma URL JSON

Ler objetos de uma URL também é bastante simples. Precisamos passar o objeto URL e o tipo da classe para o método readValue().

Adicione o seguinte código para ler e mapear objetos de uma URL JSON.

import java.net.URL;
import java.text.SimpleDateFormat;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;

public class ObjectMapperDemo {
    public static void main(String[] args) {
        try {
            URL jsonFileUrl = new URL("file:demo.json");
            ObjectMapper objMapper = new ObjectMapper().configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
            DemoClass obj = objMapper.readValue(jsonFileUrl, DemoClass.class);

            System.out.println("Field1: " + obj.getField1());
            System.out.println("Field2: " + obj.getField2());
            System.out.println("DateField: " + obj.getDateField());
        } catch (Exception e) {
            System.out.println(e);
        }
    }
}

A saída será a mesma do Passo 2.

Lendo de um Array de String JSON para um Array de Objetos

Suponha que uma string contenha dados de múltiplos objetos (como um array) em formato JSON. Podemos ler todos esses dados em um array do tipo DemoClass usando a classe ObjectMapper.

Adicione o seguinte código para ler objetos de um array de string JSON para um array de objetos.

String jsonString = " [{\"field1\":\"Sample-1\",\"field2\":20.21,\"dateField\":\"2021-07-30T14:20:30.000Z\"}," +
        " {\"field1\":\"Sample-2\",\"field2\":22.55,\"dateField\":\"2021-07-31T14:20:30.000Z\"}]";

ObjectMapper objMapper = new ObjectMapper();
DemoClass[] objectArr = objMapper.readValue(jsonString, DemoClass[].class);

for (DemoClass obj : objectArr) {
    System.out.println("Field1: " + obj.getField1());
    System.out.println("Field2: " + obj.getField2());
    System.out.println("DateField: " + obj.getDateField());
    System.out.println();
}

A saída será:

Field1: Sample-1
Field2: 20.21
DateField: Fri Jul 30 14:20:30 UTC 2021

Field1: Sample-2
Field2: 22.55
DateField: Sat Jul 31 14:20:30 UTC 2021

Lendo de um Array de String JSON para uma Lista de Objetos

Podemos ler os objetos em uma lista se não quisermos ler os dados em um array de objetos de tamanho fixo.

Adicione o seguinte código para ler objetos de um array de string JSON para uma lista de objetos.

String jsonString = " [{\"field1\":\"Sample-1\",\"field2\":20.21,\"dateField\":\"2021-07-30T14:20:30.000Z\"}," +
        " {\"field1\":\"Sample-2\",\"field2\":22.55,\"dateField\":\"2021-07-31T14:20:30.000Z\"}]";

ObjectMapper objMapper = new ObjectMapper();
ArrayList<DemoClass> objectList = objMapper.readValue(jsonString, new TypeReference<ArrayList<DemoClass>>(){});

for (DemoClass obj : objectList) {
    System.out.println("Field1: " + obj.getField1());
    System.out.println("Field2: " + obj.getField2());
    System.out.println("DateField: " + obj.getDateField());
    System.out.println();
}

A saída será a mesma do Passo 5.

Lendo de um Array de String JSON para um Mapa de Objetos

Também podemos ler dados de uma string JSON para um mapa. Cada propriedade da classe se tornará uma chave, e o valor da propriedade se tornará o valor.

Adicione o seguinte código para ler dados de um array de string JSON para um mapa.

String jsonString = "{\"field1\":\"Sample-1\",\"field2\":20.21,\"dateField\":\"2021-07-30T14:20:30.000Z\"}";

ObjectMapper objMapper = new ObjectMapper();
Map<String, Object> objectMap = objMapper.readValue(jsonString, new TypeReference<Map<String, Object>>() {});

for (Map.Entry<String, Object> entry : objectMap.entrySet()) {
    System.out.println(entry.getKey() + ": " + entry.getValue());
}

A saída será:

field1: Sample-1
field2: 20.21
dateField: 2021-07-30T14:20:30.000Z

Lendo JSON para um Objeto JsonNode

A classe JsonNode nos fornece uma maneira mais flexível de analisar JSON. Podemos usar o método readTree() da classe ObjectMapper para ler JSON em um objeto JsonNode.

Adicione o seguinte código para ler JSON para um objeto JsonNode.

String jsonString = "{\"field1\":\"Sample-1\",\"field2\":20.21,\"dateField\":\"2021-07-30T14:20:30.000Z\"}";

ObjectMapper objMapper = new ObjectMapper();
JsonNode node = objMapper.readTree(jsonString);

System.out.println("Field1: " + node.get("field1").asText());
System.out.println("Field2: " + node.get("field2").asDouble());
System.out.println("DateField: " + node.get("dateField").asText());

A saída será a mesma do Passo 2.

Configurando ObjectMapper

Podemos configurar o ObjectMapper para que ele possa trabalhar com entradas inesperadas.

Adicione o seguinte código para configurar o ObjectMapper para ignorar quaisquer novas propriedades.

String jsonString = "{\"field1\":\"Sample-1\",\"field2\":20.21,\"field3\":\"Unknown\"}";

ObjectMapper objMapper = new ObjectMapper().configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
DemoClass obj = objMapper.readValue(jsonString, DemoClass.class);

System.out.println("Field1: " + obj.getField1());
System.out.println("Field2: " + obj.getField2());
System.out.println("DateField: " + obj.getDateField());

A saída será a mesma do Passo 2.

Trabalhando com Datas

Por padrão, o ObjectMapper mapeará um java.util.date para um valor long. Este valor long é o número de milissegundos passados desde 1º de janeiro de 1970.

Adicione o seguinte código para demonstrar como definir um formato de data usando o SimpleDateFormat para serializar o java.util.date.

ObjectMapper objMapper = new ObjectMapper();

SimpleDateFormat dateFormat = new SimpleDateFormat("dd-MM-yyyy");
objMapper.setDateFormat(dateFormat);

DemoClass obj = new DemoClass("Sample-1", 20.21, new Date());
String jsonString = objMapper.writeValueAsString(obj);

System.out.println(jsonString);

A saída será:

{"field1":"Sample-1","field2":20.21,"dateField":"30-07-2021"}

Resumo

Neste laboratório, aprendemos como usar a classe ObjectMapper do Jackson para mapear objetos para JSON e JSON para objetos. Aprendemos como ler um arquivo JSON em um objeto, ler dados de uma string JSON e mapeá-los para um objeto, e ler objetos de um array de string JSON para uma lista ou array de objetos. Também aprendemos como ler uma string JSON em um objeto JsonNode e configurar o ObjectMapper para ignorar novas propriedades ou valores nulos para tipos primitivos. Finalmente, aprendemos como trabalhar com datas e usar um formato de data específico ao serializar o java.util.date.