Nov 082014
 
Artículo Java

JSON es un formato cada vez más extendido para el intercambio de datos entre aplicaciones. La manera más sencilla de procesar un fichero JSON es utilizar un conversor que lee el contenido completo en memoria, en forma de un árbol de estructuras de datos.

Pero en ocasiones, el volumen de datos a procesar es demasiado elevado, y los recursos de memoria disponibles son insuficientes para utilizar este mecanismo. En estos casos, hay que implementar la lectura en “streaming”, en la cual el contenido del documento JSON se va leyendo y procesando secuencialmente, elemento a elemento.

En este artículo se realiza una introducción a la librería “Jackson”, que permite llevar a cabo este tipo de proceso secuencial en un programa Java.

1. Descarga e instalación de la librería Jackson Core

Los distintos módulos de que se compone Jackson se pueden descargar desde el Repositorio Central de Maven.

En primer lugar, descargamos el fichero jackson-core-2.4.3.jar, correspondiente a la versión estable más reciente (Jackson 2.4.3, de 04-Oct-2014)

en el momento de escribir este artículo, según se indica en la página principal de Jackson en github.

Opcionalmente, podemos también descargar la documentación jackson-core-2.4.3-javadoc.jar que se encuentra en el mismo directorio.

2. Crear un objeto parser para leer el contenido del documento JSON

Supongamos que el documento a leer se encuentra en un fichero denominado “datos.json”. Para obtener un parser de dicho documento, creamos primero un objeto JacksonFactory, y utilizamos el método “createParser()” del mismo para obtener un objeto JsonParser:

import java.io.File;
import java.io.IOException;
import com.fasterxml.jackson.core.JsonFactory;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonToken;

public class LeeJsonStream {
    public static void main(String[] args) throws IOException {
        JsonFactory factory = new JsonFactory();
        JsonParser parser = factory.createParser(new File("datos.json"));
            ...
    }
}

Nota: Además de un objeto de tipo File, el método createParser admite otros tipos de objeto como argumentos, como por ejemplo un InputStream o un objeto URL. Así, por ejemplo, si el documento a leer está en una url “http://www.ejemplo.com/datos.json”, la llamada a createParser sería de la forma:

    JsonParser parser = factory.createParser(new URL("http://www.ejemplo.com/datos.json"));

2. Leer el documento en un bucle, elemento a elemento

A continuación, leemos el contenido del documento en un bucle que incluye una llamada a parser.nextToken(), hasta que se alcanza el final del fichero:

    while (!parser.isClosed()) {
        // leer el elemento
        JsonToken token = parser.nextToken();
        // si la llamada a nextToken devuelve null, se ha alcanzado el final del fichero
        if (token == null)
            break;

        // Procesar el elemento leido
         String margen = "";
         procesaValorJSON(token, parser, margen);
    }

3. Procesar el elemento leído

Cuando un elemento ha sido leido en el objeto token, debemos determinar el tipo de elemento de que se trata, y procesarlo adecuadamente. En la clase JsonToken están definidas las constantes que identifican los distintos tipos de objeto:

  • START_OBJECT, END_OBJECT – Coressponden a los elementos “{” y “}”
  • START_ARRAY, END_ARRAY – Corresponden a los elementos “[” y “]”
  • FIELD_NAME – Nombre de un campo en un objeto JSON
  • VALUE_NULL – Literal “null”
  • VALUE_FALSE, VALUE_TRUE – Literales “false” y “true”
  • VALUE_NUMBER_INT, VALUE_NUMBER_FLOAT – Valores numéricos enteros o con decimales
  • VALUE_STRING – Cadenas de texto

Así, por ejemplo, implementamos el proceso de los valores leidos mediante unos métodos procesaValorJSON(), procesaObjetoJSON() y procesaArrayJSON(), que imprimen en pantalla el objeto con una indentación:

 private static void procesaObjetoJSON(JsonParser parser, String margen)
                     throws IOException {
     System.out.println(margen + "Encontrado Objeto");
     margen = margen + " ";
     while (!parser.isClosed()) {
         JsonToken token = parser.nextToken();
         if (JsonToken.END_OBJECT.equals(token)) {
             //Hemos alcanzado el final del objeto
             break;
         }
         if (!JsonToken.FIELD_NAME.equals(token)) {
             System.out.println("Error. esperado un nombre de campo");
             break;
         }
         System.out.println(margen + "Campo: " + parser.getCurrentName());
         token = parser.nextToken();
         procesaValorJSON(token, parser, margen);
     }
 }

 private static void procesaArrayJSON(JsonParser parser, String margen)
                     throws IOException {
     System.out.println(margen + "Encontrado Array");
     margen = margen + " ";
     while (!parser.isClosed()) {
         JsonToken token = parser.nextToken();
         if (JsonToken.END_ARRAY.equals(token)) {
             //Hemos alcanzado el final del array
             break;
         }
         procesaValorJSON(token, parser, margen);
     }
 }

 private static void procesaValorJSON(JsonToken token, JsonParser parser, String margen)
                     throws IOException {
     if (JsonToken.START_OBJECT.equals(token)) {
         procesaObjetoJSON(parser, margen);
     } else if (JsonToken.START_ARRAY.equals(token)) {
         procesaArrayJSON(parser, margen);
     } else {
         System.out.println(margen + "Valor: " + parser.getValueAsString());
     }
 }

Si el valor leído es a un objeto o un array JSON, los métodos procesaObjetoJSON y procesaValorJSON son llamados recursivamente.

Si el valor leído es boleano, numérico o texto, se imprime simplemente su valor con el método getValueAsString().

Referencias

Indice de artículos sobre programación en lenguaje Java

 Publicado por en 12:38 pm

 Deja un comentario

(requerido)

(requerido)