Java XML y JSON: procesamiento de documentos para Java SE, Parte 2: JSON-B

En este artículo, continuaremos explorando XML y JSON en Java 11 y más allá.

Los ejemplos de este artículo le presentarán JSON-B, la API de enlace JSON para Java. Después de una descripción general rápida y las instrucciones de instalación, le mostraré cómo usar JSON-B para serializar y deserializar objetos, matrices y colecciones de Java; cómo personalizar la serialización y deserialización usando JSON-B; y cómo utilizar adaptadores JSON-B para convertir objetos de origen en objetos de destino durante la serialización o deserialización.

El material de este artículo es completamente nuevo, pero podría considerarse un capítulo adicional (Capítulo 13) para mi nuevo libro, publicado recientemente por Apress: Java XML and JSON, Second Edition .

Acerca del libro: Java XML y JSON

Como compartí en mi artículo anterior, Apress acaba de publicar la segunda edición de mi libro, Java XML y JSON . Ha sido un placer escribir un libro completo sobre XML y JSON, dos tecnologías que considero más complementarias que competitivas. Después de la publicación del libro, agregué nuevos ejemplos para el Capítulo 6: Transformación de documentos XML con XSLT y para el Capítulo 11: Procesamiento de JSON con Jackson. Mi último artículo, "Java XML y JSON: procesamiento de documentos para Java SE, Parte 1" introdujo una variedad de técnicas de procesamiento y transformación de documentos utilizando SAXON y Jackson. Asegúrese de consultar ese artículo para obtener más información sobre estas técnicas.

Obtener el código

Descargue el código fuente para ver los ejemplos utilizados en este tutorial.

¿Qué es JSON-B?

JSON-B es una capa de enlace estándar y una API para convertir objetos Java hacia y desde documentos JSON. Es similar a Java Architecture for XML Binding (JAXB), que se utiliza para convertir objetos Java hacia y desde XML.

JSON-B se basa en JSON-P, la API de procesamiento JSON que se utiliza para analizar, generar, consultar y transformar documentos JSON. JSON-B fue introducido por Java Specification Request (JSR) 367 más de un año después del lanzamiento final de JSR 353, el JSR para JSON-P.

La API JSON-B

El sitio web Java API for JSON Binding (JSON-B) presenta JSON-B y proporciona acceso a varios recursos, incluida la documentación de la API. Según la documentación, el módulo JSON-B almacena seis paquetes:

  • javax.json.bind: Define el punto de entrada para vincular objetos Java a documentos JSON.
  • javax.json.bind.adapter: Define clases relacionadas con el adaptador.
  • javax.json.bind.annotation: Define anotaciones para personalizar la asignación entre los elementos del programa Java y los documentos JSON.
  • javax.json.bind.config: Define estrategias y políticas para personalizar el mapeo entre los elementos del programa Java y los documentos JSON.
  • javax.json.bind.serializer: Define interfaces para crear serializadores y deserializadores personalizados.
  • javax.json.bind.spi: Define una interfaz de proveedor de servicios (SPI) para conectar correos electrónicos personalizados JsonbBuilder.

El sitio web JSON-B también proporciona un enlace a Yasson, un marco de Java que proporciona una capa de enlace estándar entre las clases de Java y los documentos JSON, y una implementación de referencia oficial de la API de enlace JSON.

JSON-B y Java EE 8

Al igual que JSON-P, JSON-B se consideró originalmente para su inclusión en Java SE, pero en su lugar se incluyó en la versión Java EE 8. Sin embargo, aún puede trabajar con JSON-B en un contexto Java SE.

Descargue e instale JSON-B

JSON-B 1.0 es la versión actual en el momento de escribir este artículo. Puede obtener la implementación de referencia de Yasson de esta biblioteca en el repositorio de Maven. Deberá descargar los siguientes archivos JAR:

  • Javax JSON Bind API 1.0: contiene todos los archivos de clase JSON-B. Descargué javax.json.bind-api-1.0.jar.
  • Yasson: contiene la implementación de referencia basada en Eclipse de JSON-B. Descargué yasson-1.0.3.jar.
  • Proveedor predeterminado JSR 374 (procesamiento JSON): contiene todos los archivos de clase JSON-P 1.0 junto con los archivos de clase del proveedor predeterminado de Glassfish. Descargué javax.json-1.1.4.jar.

Agregue estos archivos JAR a su classpath cuando compile y ejecute código que use estas bibliotecas:

javac -cp javax.json.bind-api-1.0.jar;. main source file java -cp javax.json.bind-api-1.0.jar;yasson-1.0.3.jar;javax.json-1.1.4.jar;. main classfile

Serializar y deserializar objetos Java con JSON-B

El javax.json.bindpaquete proporciona las interfaces Jsonby JsonbBuilder, que sirven como punto de entrada a esta biblioteca:

  • Jsonbproporciona toJson()métodos sobrecargados para serializar árboles de objetos Java en documentos JSON y fromJson()métodos para deserializar documentos JSON en árboles de objetos Java.
  • JsonbBuilderproporciona newBuilder()y otros métodos para obtener un nuevo constructor build()y create()métodos para devolver nuevos Jsonbobjetos.

El siguiente ejemplo de código demuestra el uso básico de los tipos Jsonby JsonBuilder:

// Create a new Jsonb instance using the default JsonbBuilder implementation. Jsonb jsonb = JsonbBuilder.create(); // Create an Employee object from a hypothetical Employee class. Employee employee = ... // Convert the Employee object to a JSON document stored in a string. String jsonEmployee = jsonb.toJson(employee); // Convert the previously-created JSON document to an Employee object. Employee employee2 = jsonb.fromJson(jsonEmployee, Employee.class);

Este ejemplo invoca Jsonbel String toJson(Object object)método de serializar un objeto Java, ( Employee). Este método se pasa a la raíz del árbol de objetos de Java para serializar. Si nullse pasa, toJson()lanza java.lang.NullPointerException. Se javax.json.bind.JsonbExceptionproduce cuando ocurre un problema inesperado (como un error de E / S) durante la serialización.

Este fragmento de código también invoca Jsonbel T fromJson(String str, Class type)método genérico, que se utiliza para la deserialización. A este método se le pasa el documento JSON basado en cadenas para deserializar y el tipo de objeto raíz del árbol de objetos Java resultante, que se devuelve. Este método arroja NullPointerExceptioncuando nullse pasa a cualquier parámetro; se lanza JsonbExceptioncuando se produce un problema inesperado durante la deserialización.

Extraje el fragmento de código de una JSONBDemoaplicación que proporciona una demostración básica de JSON-B. El Listado 1 presenta el código fuente de esta demostración.

Listado 1. JSONBDemo.java (versión 1)

import java.time.LocalDate; import javax.json.bind.Jsonb; import javax.json.bind.JsonbBuilder; public class JSONBDemo { public static void main(String[] args) { Jsonb jsonb = JsonbBuilder.create(); Employee employee = new Employee("John", "Doe", 123456789, false, LocalDate.of(1980, 12, 23), LocalDate.of(2002, 8, 14)); String jsonEmployee = jsonb.toJson(employee); System.out.println(jsonEmployee); System.out.println(); Employee employee2 = jsonb.fromJson(jsonEmployee, Employee.class); System.out.println(employee2); } }

main()primero crea un Jsonbobjeto seguido de un Employeeobjeto. Luego llama toJson()para serializar el Employeeobjeto en un documento JSON que está almacenado en una cadena. Después de imprimir este documento, main()invoca fromJson()con la cadena anterior y Employeeel java.lang.Classobjeto de deserializar el documento JSON a otro Employeeobjeto, que posteriormente se imprime.

El Listado 2 presenta Employeeel código fuente.

Listado 2. Employee.java (versión 1)

import java.time.LocalDate; public class Employee { private String firstName; private String lastName; private int ssn; private boolean isMarried; private LocalDate birthDate; private LocalDate hireDate; private StringBuffer sb = new StringBuffer(); public Employee() {} public Employee(String firstName, String lastName, int ssn, boolean isMarried, LocalDate birthDate, LocalDate hireDate) { this.firstName = firstName; this.lastName = lastName; this.ssn = ssn; this.isMarried = isMarried; this.birthDate = birthDate; this.hireDate = hireDate; } public String getFirstName() { return firstName; } public String getLastName() { return lastName; } public int getSSN() { return ssn; } public boolean isMarried() { return isMarried; } public LocalDate getBirthDate() { return birthDate; } public LocalDate getHireDate() { return hireDate; } public void setFirstName(String firstName) { this.firstName = firstName; } public void setLastName(String lastName) { this.lastName = lastName; } public void setSSN(int ssn) { this.ssn = ssn; } public void setIsMarried(boolean isMarried) { this.isMarried = isMarried; } public void setBirthDate(LocalDate birthDate) { this.birthDate = birthDate; } public void setHireDate(LocalDate hireDate) { this.hireDate = hireDate; } @Override public String toString() { sb.setLength(0); sb.append("First name ["); sb.append(firstName); sb.append("], Last name ["); sb.append(lastName); sb.append("], SSN ["); sb.append(ssn); sb.append("], Married ["); sb.append(isMarried); sb.append("], Birthdate ["); sb.append(birthDate); sb.append("], Hiredate ["); sb.append(hireDate); sb.append("]"); return sb.toString(); } }

Compile los listados 1 y 2 de la siguiente manera:

javac -cp javax.json.bind-api-1.0.jar;. JSONBDemo.java

Ejecute la aplicación de la siguiente manera:

java -cp javax.json.bind-api-1.0.jar;yasson-1.0.3.jar;javax.json-1.1.4.jar;. JSONBDemo

You should observe the following output (spread across multiple lines for readability):

{"SSN":123456789,"birthDate":"1980-12-23","firstName":"John","hireDate":"2002-08-14", "lastName":"Doe","married":false} First name [John], Last name [Doe], SSN [123456789], Married [false], Birthdate [1980-12-23], Hiredate [2002-08-14] 

Rules for working with JSON-B

While playing with this application, I observed some interesting behaviors that led me to formulate the following rules concerning Employee:

  • The class must be public; otherwise, an exception is thrown.
  • toJson() will not serialize fields with non-public getter methods.
  • fromJson() will not deserialize fields with non-public setter methods.
  • fromJson() throws JsonbException in the absence of a public noargument constructor.

In order to seamlessly convert between Java object fields and JSON data, JSON-B has to support various Java types. For example, JSON-B supports the following basic Java types:

  • java.lang.Boolean
  • java.lang.Byte
  • java.lang.Character
  • java.lang.Double
  • java.lang.Float
  • java.lang.Integer
  • java.lang.Long
  • java.lang.Short
  • java.lang.String

Tipos adicionales, tales como java.math.BigInteger, java.util.Date, y java.time.LocalDateson compatibles. Consulte la especificación JSON-B para obtener una lista completa de los tipos admitidos.

Serializar y deserializar matrices y colecciones con JSON-B

La sección anterior se centró en la serialización y deserialización de objetos Java individuales. JSON-B también admite la capacidad de serializar y deserializar matrices y colecciones de objetos. El Listado 3 proporciona una demostración.

Listado 3. JSONBDemo.java (versión 2)

import java.time.LocalDate; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import javax.json.bind.Jsonb; import javax.json.bind.JsonbBuilder; public class JSONBDemo { public static void main(String[] args) { arrayDemo(); listDemo(); } // Serialize and deserialize an array of Employee objects. static void arrayDemo() { Jsonb jsonb = JsonbBuilder.create(); Employee[] employees = { new Employee("John", "Doe", 123456789, false, LocalDate.of(1980, 12, 23), LocalDate.of(2002, 8, 14)), new Employee("Jane", "Smith", 987654321, true, LocalDate.of(1982, 6, 13), LocalDate.of(2001, 2, 9)) }; String jsonEmployees = jsonb.toJson(employees); System.out.println(jsonEmployees); System.out.println(); employees = null; employees = jsonb.fromJson(jsonEmployees, Employee[].class); for (Employee employee: employees) { System.out.println(employee); System.out.println(); } } // Serialize and deserialize a List of Employee objects. static void listDemo() { Jsonb jsonb = JsonbBuilder.create(); List employees = Arrays.asList(new Employee("John", "Doe", 123456789, false, LocalDate.of(1980, 12, 23), LocalDate.of(2002, 8, 14)), new Employee("Jane", "Smith", 987654321, true, LocalDate.of(1982, 6, 13), LocalDate.of(1999, 7, 20))); String jsonEmployees = jsonb.toJson(employees); System.out.println(jsonEmployees); System.out.println(); employees = null; employees = jsonb.fromJson(jsonEmployees, new ArrayList(){}. getClass().getGenericSuperclass()); System.out.println(employees); } }

El Listado 3 es una extensión simple del Listado 1 y usa la misma Employeeclase presentada en el Listado 2. Además, este ejemplo de código llama a los mismos métodos toJson()y fromJson().