Generar, procesar y modificar documentos JSON con JSON-P en Java

Escrito por el .
java planeta-codigo programacion
Comentarios

Java

Los servicios que ofrecen una API REST normalmente emplean JSON como formato para intercambiar datos tanto en las peticiones como en las respuestas. En Java hay varias formas de generar y procesar JSON para obtener los datos que contiene.

Una de las formas estándar es usando la especificación JSON-P que convierte un JSON a una estructura de objetos Java que representan los datos del JSON como son los objetos Json, JsonObject, JsonArray, JsonString o JsonNumber. Esta API permite convertir una cadena de texto en formato JSON a objetos de la API y una jerarquía de objetos de la API a una cadena.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
package io.github.picodotdev.blogbitix.javajson;

...

public class Main {

    public static void main(String[] args) throws Exception {
        Comprador comprador = buildComprador();
        String json = "";

        // JSON-P
        JsonObject jsonp = Json.createObjectBuilder()
            .add("name", comprador.getNombre())
            .add("edad", comprador.getEdad())
            .add("direcciones", Json.createArrayBuilder().add(
                Json.createObjectBuilder()
                    .add("calle", comprador.getDirecciones().get(0).getCalle())
                    .add("ciudad", comprador.getDirecciones().get(0).getCiudad())
                    .add("codigoPostal", comprador.getDirecciones().get(0).getCodigoPostal())
                    .add("pais", comprador.getDirecciones().get(0).getPais())
                    .build())
                .add(Json.createObjectBuilder()
                    .add("calle", comprador.getDirecciones().get(1).getCalle())
                    .add("ciudad", comprador.getDirecciones().get(1).getCiudad())
                    .add("codigoPostal", comprador.getDirecciones().get(1).getCodigoPostal())
                    .add("pais", comprador.getDirecciones().get(1).getPais()))
                    .build()
            ).build();
        json = jsonp.toString();
        jsonp = Json.createReader(new StringReader(json)).readObject();
        System.out.printf("JSON-P: %s%n", json);
        System.out.printf("JSON-P (JsonObject): %s%n", jsonp.toString());
        
        ...
    }

    private static Comprador buildComprador() {
        Comprador comprador = new Comprador();
        comprador.setNombre("Juan");
        comprador.setEdad(30);
        comprador.getDirecciones().add(buildDireccion());
        comprador.getDirecciones().add(buildDireccion());
        return comprador;
    }

    private static Direccion buildDireccion() {
        return new Direccion("calle", "ciudad", "codigoPostal", "pais");
    }
}
1
2
JSON-P: {"name":"Juan","edad":30,"direcciones":[{"calle":"calle","ciudad":"ciudad","codigoPostal":"codigoPostal","pais":"pais"},{"calle":"calle","ciudad":"ciudad","codigoPostal":"codigoPostal","pais":"pais"}]}
JSON-P (JsonObject): {"name":"Juan","edad":30,"direcciones":[{"calle":"calle","ciudad":"ciudad","codigoPostal":"codigoPostal","pais":"pais"},{"calle":"calle","ciudad":"ciudad","codigoPostal":"codigoPostal","pais":"pais"}]}

JSON-P permite analizar un JSON recibiendo un flujo de eventos en su lectura con la Stream API además de soportar las especificaciones JSON Pointer para construir una referencia a una valor del documento JSON que junto con JSON Patch y JSON Merge Patch permite realizar operaciones de modificación a un documento JSON o un recurso en una API REST con el verbo PATCH de HTTP. Las clases en la API son JsonPointer, JsonPatch y JsonMergePatch.

En el ejemplo se agrega un nuevo campo y se elimina un elemento de un array a un documento JSON haciendo uso de JSON Pointer y JSON Patch. En los documentos de las especificaciones se incluyen algunos ejemplos.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
package io.github.picodotdev.blogbitix.javajson;

...

public class Main {

    public static void main(String[] args) throws Exception {
        ...

        JsonPatch jsonPatch = Json.createPatchBuilder().add("/telefono", "111111111").remove("/direcciones/0").build();
        jsonp = jsonPatch.apply(jsonp);
        System.out.printf("JSON-P (JsonPatch): %s%n", jsonPatch.toString());
        System.out.printf("JSON-P (JsonObject): %s%n", jsonp.toString());

        ...
}
1
2
JSON-P (JsonPatch): [{"op":"add","path":"/telefono","value":"111111111"},{"op":"remove","path":"/direcciones/0"}]
JSON-P (JsonObject): {"name":"Juan","edad":30,"direcciones":[{"calle":"calle","ciudad":"ciudad","codigoPostal":"codigoPostal","pais":"pais"}],"telefono":"111111111"}

JSON-P es una API de bajo nivel para procesar JSON y un tanto engorrosa de utilizar, no es la única forma utilizable. También está la especificación JSON-B que va un poco más lejos que JSON-P y ofrece una forma de hacer una correspondencia entre el JSON y tipos propios en Java que siguen las convenciones de los Java Bean, con esto se aprovecha la validación de tipos de Java. Las librerías Gson y Jackson también ofrece soporte para tratar con JSON de forma parecida a JSON-B. Otra alternativa es utilizar JsonPath que permite extraer datos de una cadena JSON con expresiones de selección.

El código fuente completo del ejemplo puedes descargarlo del repositorio de ejemplos de Blog Bitix alojado en GitHub y probarlo en tu equipo ejecutando el comando ./gradlew run.