Mapeo de objetos con la biblioteca Jackson

Beginner

💡 Este tutorial está traducido por IA desde la versión en inglés. Para ver la versión original, puedes hacer clic aquí

Introducción

En este laboratorio, aprenderemos a usar la clase ObjectMapper de Jackson para mapear objetos a JSON y JSON a objetos. Usaremos una clase Java simple llamada DemoClass y aprenderemos varias técnicas para leer y escribir datos JSON.


Skills Graph

Crear y compilar DemoClass

Crea un nuevo proyecto en el directorio ~/proyecto y crea una nueva clase Java DemoClass. Pega el siguiente código en el archivo de código DemoClass.java.

import java.util.Date;

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

    // Constructores
    DemoClass() {}

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

    // getters y 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;
    }
}

Compila la clase Java DemoClass usando el siguiente comando:

javac DemoClass.java

Leyendo objetos desde un archivo JSON

Podemos usar el método readValue() de la clase ObjectMapper para leer datos de un archivo JSON y convertirlos en un objeto. Nuestro archivo JSON contiene solo los pares propiedad-valor de un solo objeto.

Crea un nuevo archivo llamado demo.json y pega el siguiente contenido JSON en él.

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

Usa el siguiente código para leer el archivo JSON y mapearlo a un 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);
        }
    }
}

La salida será:

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

Leyendo objetos desde una cadena JSON

Podemos leer datos de una cadena JSON y convertirlos en un objeto. Usaremos el método readValue() de la clase ObjectMapper. También necesitamos pasar el tipo de clase a este método.

Agrega el siguiente código para leer datos de una cadena 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());

La salida será:

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

Leyendo objetos desde una URL JSON

Leer objetos desde una URL también es bastante sencillo. Necesitamos pasar el objeto URL y el tipo de clase al método readValue().

Agrega el siguiente código para leer y mapear objetos desde una 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);
        }
    }
}

La salida será la misma que en el Paso 2.

Leyendo desde una matriz de cadenas JSON a una matriz de objetos

Supongamos que una cadena contiene datos de múltiples objetos (como una matriz) en formato JSON. Podemos leer todos estos datos en una matriz del tipo DemoClass usando la clase ObjectMapper.

Agrega el siguiente código para leer objetos desde una matriz de cadenas JSON a una matriz 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();
}

La salida 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

Leyendo desde una matriz de cadenas JSON a una lista de objetos

Podemos leer los objetos en una lista si no queremos leer los datos en una matriz de objetos de tamaño fijo.

Agrega el siguiente código para leer objetos desde una matriz de cadenas JSON a una 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();
}

La salida será la misma que en el Paso 5.

Leyendo desde una matriz de cadenas JSON a un mapa de objetos

También podemos leer datos de una cadena JSON en un mapa. Cada propiedad de la clase se convertirá en una clave y el valor de la propiedad se convertirá en el valor.

Agrega el siguiente código para leer datos de una matriz de cadenas JSON en un 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());
}

La salida será:

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

Leyendo JSON a un objeto JsonNode

La clase JsonNode nos proporciona una forma más flexible de analizar JSON. Podemos usar el método readTree() de la clase ObjectMapper para leer JSON en un objeto JsonNode.

Agrega el siguiente código para leer JSON en un 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());

La salida será la misma que en el Paso 2.

Configurando ObjectMapper

Podemos configurar el ObjectMapper para que funcione con entradas inesperadas.

Agrega el siguiente código para configurar el ObjectMapper para ignorar cualquier nueva propiedad.

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

La salida será la misma que en el Paso 2.

Trabajando con fechas

Por defecto, el ObjectMapper mapeará un java.util.date a un valor largo. Este valor largo es el número de milisegundos transcurridos desde el 1 de enero de 1970.

Agrega el siguiente código para demostrar cómo definir un formato de fecha usando SimpleDateFormat para serializar el 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);

La salida será:

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

Resumen

En este laboratorio, aprendimos cómo usar la clase ObjectMapper de Jackson para mapear objetos a JSON y JSON a objetos. Aprendimos cómo leer un archivo JSON en un objeto, leer datos de una cadena JSON y mapearlos a un objeto, y leer objetos de una matriz de cadenas JSON a una lista o matriz de objetos. También aprendimos cómo leer una cadena JSON en un objeto JsonNode y configurar el ObjectMapper para ignorar nuevas propiedades o valores nulos para tipos primitivos. Finalmente, aprendimos cómo trabajar con fechas y usar un formato de fecha específico al serializar el java.util.date.