Ejemplo de tutorial de la API del Analizador Jackson JSON en Java

El analizador Jackson JSON Java es muy popular y se utiliza también en el marco de Spring. La API de procesamiento de JSON de Java no es muy amigable para el usuario y no proporciona características para la transformación automática de Json a objeto Java y viceversa. Afortunadamente, tenemos algunas API alternativas que podemos usar para el procesamiento de JSON. En el último artículo aprendimos sobre Google Gson API y vimos lo fácil que es usarlo.

El analizador Jackson JSON Java

Para usar la API de Jackson JSON Java en nuestro proyecto, podemos agregarla al camino de construcción del proyecto o, si estamos utilizando Maven, podemos agregar la siguiente dependencia.

<dependency>
	<groupId>com.fasterxml.jackson.core</groupId>
	<artifactId>jackson-databind</artifactId>
	<version>2.2.3</version>
</dependency>

El archivo jar jackson-databind depende de las bibliotecas jackson-core y jackson-annotations, así que si las estás agregando directamente al camino de construcción, asegúrate de agregar las tres, de lo contrario, obtendrás un error en tiempo de ejecución. La API del Analizador JSON de Jackson proporciona una manera fácil de convertir JSON a un objeto POJO y admite una conversión fácil a Mapa desde datos JSON. Jackson también admite genéricos y los convierte directamente de JSON a objeto.

Ejemplo de JSON de Jackson

Para nuestro ejemplo de conversión de JSON a POJO/objeto Java, tomaremos un ejemplo complejo con objetos y matrices anidadas. Usaremos matrices, listas y Mapas en objetos Java para la conversión. Nuestro JSON complejo se almacena en un archivo employee.txt con la siguiente estructura:

{
  "id": 123,
  "name": "Pankaj",
  "permanent": true,
  "address": {
    "street": "Albany Dr",
    "city": "San Jose",
    "zipcode": 95129
  },
  "phoneNumbers": [
    123456,
    987654
  ],
  "role": "Manager",
  "cities": [
    "Los Angeles",
    "New York"
  ],
  "properties": {
    "age": "29 years",
    "salary": "1000 USD"
  }
}

Tenemos las siguientes clases Java correspondientes a los datos JSON.

package com.journaldev.jackson.model;

public class Address {
	
	private String street;
	private String city;
	private int zipcode;
	
	public String getStreet() {
		return street;
	}
	public void setStreet(String street) {
		this.street = street;
	}
	public String getCity() {
		return city;
	}
	public void setCity(String city) {
		this.city = city;
	}
	public int getZipcode() {
		return zipcode;
	}
	public void setZipcode(int zipcode) {
		this.zipcode = zipcode;
	}
	
	@Override
	public String toString(){
		return getStreet() + ", "+getCity()+", "+getZipcode();
	}
}

La clase Address corresponde al objeto interno en los datos JSON raíz.

package com.journaldev.jackson.model;

import java.util.Arrays;
import java.util.List;
import java.util.Map;

public class Employee {

	private int id;
	private String name;
	private boolean permanent;
	private Address address;
	private long[] phoneNumbers;
	private String role;
	private List<String> cities;
	private Map<String, String> properties;
	
	public int getId() {
		return id;
	}
	public void setId(int id) {
		this.id = id;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public boolean isPermanent() {
		return permanent;
	}
	public void setPermanent(boolean permanent) {
		this.permanent = permanent;
	}
	public Address getAddress() {
		return address;
	}
	public void setAddress(Address address) {
		this.address = address;
	}
	public long[] getPhoneNumbers() {
		return phoneNumbers;
	}
	public void setPhoneNumbers(long[] phoneNumbers) {
		this.phoneNumbers = phoneNumbers;
	}
	public String getRole() {
		return role;
	}
	public void setRole(String role) {
		this.role = role;
	}
	
	@Override
	public String toString(){
		StringBuilder sb = new StringBuilder();
		sb.append("***** Employee Details *****\n");
		sb.append("ID="+getId()+"\n");
		sb.append("Name="+getName()+"\n");
		sb.append("Permanent="+isPermanent()+"\n");
		sb.append("Role="+getRole()+"\n");
		sb.append("Phone Numbers="+Arrays.toString(getPhoneNumbers())+"\n");
		sb.append("Address="+getAddress()+"\n");
		sb.append("Cities="+Arrays.toString(getCities().toArray())+"\n");
		sb.append("Properties="+getProperties()+"\n");
		sb.append("*****************************");
		
		return sb.toString();
	}
	public List<String> getCities() {
		return cities;
	}
	public void setCities(List<String> cities) {
		this.cities = cities;
	}
	public Map<String, String> getProperties() {
		return properties;
	}
	public void setProperties(Map<String, String> properties) {
		this.properties = properties;
	}
}

Employee es el bean Java que representa el objeto JSON raíz. Ahora veamos cómo podemos transformar JSON a objeto Java usando la API del analizador JSON de Jackson.

package com.journaldev.jackson.json;

import java.io.File;
import java.io.IOException;
import java.io.StringWriter;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.journaldev.jackson.model.Address;
import com.journaldev.jackson.model.Employee;


public class JacksonObjectMapperExample {

	public static void main(String[] args) throws IOException {
		
		// leer datos del archivo JSON como cadena
		byte[] jsonData = Files.readAllBytes(Paths.get("employee.txt"));
		
		// crear una instancia de ObjectMapper
		ObjectMapper objectMapper = new ObjectMapper();
		
		// convertir la cadena JSON a objeto
		Employee emp = objectMapper.readValue(jsonData, Employee.class);
		
		System.out.println("Employee Object\n"+emp);
		
		// convertir Objeto a cadena JSON
		Employee emp1 = createEmployee();
		// configurar el mapeador de objetos para imprimir bonito
		objectMapper.configure(SerializationFeature.INDENT_OUTPUT, true);
		
		// escribir en la consola, se puede escribir en cualquier flujo de salida como un archivo
		StringWriter stringEmp = new StringWriter();
		objectMapper.writeValue(stringEmp, emp1);
		System.out.println("Employee JSON is\n"+stringEmp);
	}
	
	public static Employee createEmployee() {

		Employee emp = new Employee();
		emp.setId(100);
		emp.setName("David");
		emp.setPermanent(false);
		emp.setPhoneNumbers(new long[] { 123456, 987654 });
		emp.setRole("Manager");

		Address add = new Address();
		add.setCity("Bangalore");
		add.setStreet("BTM 1st Stage");
		add.setZipcode(560100);
		emp.setAddress(add);

		List cities = new ArrayList();
		cities.add("Los Angeles");
		cities.add("New York");
		emp.setCities(cities);

		Map props = new HashMap();
		props.put("salary", "1000 Rs");
		props.put("age", "28 years");
		emp.setProperties(props);

		return emp;
	}

}

Cuando ejecutamos el programa anterior, obtendremos la siguiente salida.

Employee Object
***** Employee Details *****
ID=123
Name=Pankaj
Permanent=true
Role=Manager
Phone Numbers=[123456, 987654]
Address=Albany Dr, San Jose, 95129
Cities=[Los Angeles, New York]
Properties={age=29 years, salary=1000 USD}
*****************************
Employee JSON is
//imprimiendo los mismos datos del archivo JSON anterior 

com.fasterxml.jackson.databind.ObjectMapper es la clase más importante en la API de Jackson que proporciona los métodos readValue() y writeValue() para transformar JSON a Objeto Java y Objeto Java a JSON. La clase ObjectMapper puede ser reutilizada y podemos inicializarla una vez como objeto Singleton. Hay muchas versiones sobrecargadas de los métodos readValue() y writeValue() para trabajar con matrices de bytes, archivos, flujos de entrada/salida y objetos Reader/Writer.

Jackson JSON – Convirtiendo JSON a Mapa

A veces tenemos un objeto JSON como el siguiente, en el archivo data.txt:

{
  "name": "David",
  "role": "Manager",
  "city": "Los Angeles"
}

y queremos convertirlo en un Mapa y no en un objeto java con las mismas propiedades y claves. Podemos hacerlo muy fácilmente en la API de Jackson JSON con dos métodos con el código siguiente:

//convirtiendo json a Mapa
byte[] mapData = Files.readAllBytes(Paths.get("data.txt"));
Map myMap = new HashMap();

ObjectMapper objectMapper = new ObjectMapper();
myMap = objectMapper.readValue(mapData, HashMap.class);
System.out.println("Map is: "+myMap);

//otra forma
myMap = objectMapper.readValue(mapData, new TypeReference>() {});
System.out.println("Map using TypeReference: "+myMap);

Una vez que ejecutamos el fragmento de código anterior, obtenemos la siguiente salida:

Map is: {name=David, role=Manager, city=Los Angeles}
Map using TypeReference: {name=David, role=Manager, city=Los Angeles}

Jackson JSON – Leyendo una Clave Específica del JSON

A veces tenemos datos en formato JSON y solo nos interesan algunos de los valores de las claves, por lo que en ese caso convertir todo el JSON a un objeto no es una buena idea. La API Jackson JSON proporciona la opción de leer datos JSON como un árbol, similar a un DOM Parser, y podemos leer elementos específicos del objeto JSON a través de esto. El código a continuación ofrece un fragmento para leer entradas específicas de un archivo JSON.

//leer datos del archivo JSON como cadena
byte[] jsonData = Files.readAllBytes(Paths.get("employee.txt"));

//crear instancia de ObjectMapper
ObjectMapper objectMapper = new ObjectMapper();

//leer JSON como DOM Parser
JsonNode rootNode = objectMapper.readTree(jsonData);
JsonNode idNode = rootNode.path("id");
System.out.println("id = "+idNode.asInt());

JsonNode phoneNosNode = rootNode.path("phoneNumbers");
Iterator elements = phoneNosNode.elements();
while(elements.hasNext()){
	JsonNode phone = elements.next();
	System.out.println("Phone No = "+phone.asLong());
}

Obtenemos la siguiente salida al ejecutar el fragmento de código anterior.

id = 123
Phone No = 123456
Phone No = 987654

Jackson JSON – Editar Documento JSON

La API Jackson JSON en Java proporciona métodos útiles para agregar, editar y eliminar claves de datos JSON, y luego podemos guardarlo como un nuevo archivo JSON o escribirlo en cualquier flujo. El siguiente código nos muestra cómo hacerlo fácilmente.

byte[] jsonData = Files.readAllBytes(Paths.get("employee.txt"));

ObjectMapper objectMapper = new ObjectMapper();

//crear JsonNode
JsonNode rootNode = objectMapper.readTree(jsonData);

//actualizar datos JSON
((ObjectNode) rootNode).put("id", 500);
//agregar nuevo par clave-valor
((ObjectNode) rootNode).put("test", "test value");
//eliminar clave existente
((ObjectNode) rootNode).remove("role");
((ObjectNode) rootNode).remove("properties");
objectMapper.writeValue(new File("updated_emp.txt"), rootNode);

Si ejecutas el código anterior y buscas el nuevo archivo, notarás que no tiene las claves “role” y “properties”. También observarás que el valor de “id” se actualiza a 500 y se agrega una nueva clave “test” al archivo updated_emp.txt.

Ejemplo de la API de transmisión JSON de Jackson

La API de Java de Jackson JSON también proporciona soporte de transmisión que es útil para trabajar con grandes datos JSON porque lee todo el archivo como tokens y utiliza menos memoria. El único problema con la API de transmisión es que necesitamos cuidar todos los tokens mientras analizamos los datos JSON. Si tenemos datos JSON como {“rol”:“Gerente”}, entonces obtendremos los siguientes tokens en orden – { (inicio del objeto), “rol” (nombre de clave), “Gerente” (valor de clave) y } (fin del objeto). Dos puntos (:) son el delimitador en JSON y, por lo tanto, no se considera como un token.

package com.journaldev.jackson.json;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

import com.fasterxml.jackson.core.JsonFactory;
import com.fasterxml.jackson.core.JsonParseException;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonToken;
import com.journaldev.jackson.model.Address;
import com.journaldev.jackson.model.Employee;

public class JacksonStreamingReadExample {

	public static void main(String[] args) throws JsonParseException, IOException {
		
		//crear objeto JsonParser
		JsonParser jsonParser = new JsonFactory().createParser(new File("employee.txt"));
		
		//recorrer los tokens
		Employee emp = new Employee();
		Address address = new Address();
		emp.setAddress(address);
		emp.setCities(new ArrayList());
		emp.setProperties(new HashMap());
		List phoneNums = new ArrayList();
		boolean insidePropertiesObj=false;
		
		parseJSON(jsonParser, emp, phoneNums, insidePropertiesObj);
		
		long[] nums = new long[phoneNums.size()];
		int index = 0;
		for(Long l :phoneNums){
			nums[index++] = l;
		}
		emp.setPhoneNumbers(nums);
		
		jsonParser.close();
		//imprimir objeto de empleado
		System.out.println("Employee Object\n\n"+emp);
	}

	private static void parseJSON(JsonParser jsonParser, Employee emp,
			List phoneNums, boolean insidePropertiesObj) throws JsonParseException, IOException {
		
		//recorrer los JsonTokens
		while(jsonParser.nextToken() != JsonToken.END_OBJECT){
			String name = jsonParser.getCurrentName();
			if("id".equals(name)){
				jsonParser.nextToken();
				emp.setId(jsonParser.getIntValue());
			}else if("name".equals(name)){
				jsonParser.nextToken();
				emp.setName(jsonParser.getText());
			}else if("permanent".equals(name)){
				jsonParser.nextToken();
				emp.setPermanent(jsonParser.getBooleanValue());
			}else if("address".equals(name)){
				jsonParser.nextToken();
				//objeto anidado, llamada recursiva
				parseJSON(jsonParser, emp, phoneNums, insidePropertiesObj);
			}else if("street".equals(name)){
				jsonParser.nextToken();
				emp.getAddress().setStreet(jsonParser.getText());
			}else if("city".equals(name)){
				jsonParser.nextToken();
				emp.getAddress().setCity(jsonParser.getText());
			}else if("zipcode".equals(name)){
				jsonParser.nextToken();
				emp.getAddress().setZipcode(jsonParser.getIntValue());
			}else if("phoneNumbers".equals(name)){
				jsonParser.nextToken();
				while (jsonParser.nextToken() != JsonToken.END_ARRAY) {
					phoneNums.add(jsonParser.getLongValue());
				}
			}else if("role".equals(name)){
				jsonParser.nextToken();
				emp.setRole(jsonParser.getText());
			}else if("cities".equals(name)){
				jsonParser.nextToken();
				while (jsonParser.nextToken() != JsonToken.END_ARRAY) {
					emp.getCities().add(jsonParser.getText());
				}
			}else if("properties".equals(name)){
				jsonParser.nextToken();
				while(jsonParser.nextToken() != JsonToken.END_OBJECT){
					String key = jsonParser.getCurrentName();
					jsonParser.nextToken();
					String value = jsonParser.getText();
					emp.getProperties().put(key, value);
				}
			}
		}
	}

}

JsonParser es la API de transmisión de JSON de Jackson para leer datos JSON, la estamos utilizando para leer datos del archivo y luego el método parseJSON() se utiliza para recorrer los tokens y procesarlos para crear nuestro objeto Java. Observa que el método parseJSON() se llama recursivamente para “dirección” porque es un objeto anidado en los datos JSON. Para analizar matrices, estamos recorriendo el documento JSON. Podemos usar la clase JsonGenerator para generar datos JSON con la API de transmisión.

package com.journaldev.jackson.json;

import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Set;

import com.fasterxml.jackson.core.JsonFactory;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.util.DefaultPrettyPrinter;
import com.journaldev.jackson.model.Employee;

public class JacksonStreamingWriteExample {

	public static void main(String[] args) throws IOException {
		Employee emp = JacksonObjectMapperExample.createEmployee();

		JsonGenerator jsonGenerator = new JsonFactory()
				.createGenerator(new FileOutputStream("stream_emp.txt"));
		//para una impresión bonita
		jsonGenerator.setPrettyPrinter(new DefaultPrettyPrinter());
		
		jsonGenerator.writeStartObject(); // start root object
		jsonGenerator.writeNumberField("id", emp.getId());
		jsonGenerator.writeStringField("name", emp.getName());
		jsonGenerator.writeBooleanField("permanent", emp.isPermanent());
		
		jsonGenerator.writeObjectFieldStart("address"); //start address object
			jsonGenerator.writeStringField("street", emp.getAddress().getStreet());
			jsonGenerator.writeStringField("city", emp.getAddress().getCity());
			jsonGenerator.writeNumberField("zipcode", emp.getAddress().getZipcode());
		jsonGenerator.writeEndObject(); //end address object
		
		jsonGenerator.writeArrayFieldStart("phoneNumbers");
			for(long num : emp.getPhoneNumbers())
				jsonGenerator.writeNumber(num);
		jsonGenerator.writeEndArray();
		
		jsonGenerator.writeStringField("role", emp.getRole());
		
		jsonGenerator.writeArrayFieldStart("cities"); //start cities array
		for(String city : emp.getCities())
			jsonGenerator.writeString(city);
		jsonGenerator.writeEndArray(); //closing cities array
		
		jsonGenerator.writeObjectFieldStart("properties");
			Set keySet = emp.getProperties().keySet();
			for(String key : keySet){
				String value = emp.getProperties().get(key);
				jsonGenerator.writeStringField(key, value);
			}
		jsonGenerator.writeEndObject(); //closing properties
		jsonGenerator.writeEndObject(); //closing root object
		
		jsonGenerator.flush();
		jsonGenerator.close();
	}

}

JsonGenerator es fácil de usar en comparación con JsonParser. Eso es todo para el tutorial de referencia rápida del Analizador de JSON de Jackson para Java. La API de Jackson JSON Java es fácil de usar y proporciona muchas opciones para facilitar el trabajo de los desarrolladores con datos JSON. Descargue el proyecto desde el siguiente enlace y juegue con él para explorar más opciones sobre la API de Jackson Json.

Descargar Proyecto Jackson JSON

Referencia: Página de GitHub de Jackson

Source:
https://www.digitalocean.com/community/tutorials/jackson-json-java-parser-api-example-tutorial