Jackson JSON Java Parser API Voorbeeld Tutorial

Jackson JSON Java Parser is erg populair en wordt ook gebruikt in het Spring-framework. De Java JSON Processing API is niet erg gebruikersvriendelijk en biedt geen functies voor automatische transformatie van Json naar Java-object en vice versa. Gelukkig hebben we enkele alternatieve API’s die we kunnen gebruiken voor JSON-verwerking. In het laatste artikel hebben we geleerd over de Google Gson API en gezien hoe eenvoudig het is om het te gebruiken.

Jackson JSON Java Parser

Om de Jackson JSON Java API te gebruiken in ons project, kunnen we het toevoegen aan het build-pad van het project of als je Maven gebruikt, kunnen we de onderstaande afhankelijkheid toevoegen.

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

jackson-databind-jar is afhankelijk van de jackson-core– en jackson-annotations-bibliotheken. Als je ze rechtstreeks aan het build-pad toevoegt, zorg er dan voor dat je alle drie toevoegt, anders krijg je een runtime-fout. De Jackson JSON Parser API biedt een eenvoudige manier om JSON naar een POJO-object te converteren en ondersteunt eenvoudige conversie naar een Map vanuit JSON-gegevens. Jackson ondersteunt ook generics en zet ze direct om van JSON naar een object.

Jackson JSON Voorbeeld

Voor ons voorbeeld van JSON naar POJO/Java-objectconversie nemen we een complex voorbeeld met geneste objecten en arrays. We zullen arrays, lijsten en Map gebruiken in Java-objecten voor conversie. Onze complexe JSON is opgeslagen in een bestand met de naam employee.txt met de onderstaande structuur:

{
  "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"
  }
}

We hebben de volgende Java-klassen die overeenkomen met de JSON-gegevens.

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

De klasse Address komt overeen met het binnenste object in de root JSON-gegevens.

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 is de Java Bean die het root JSON-object vertegenwoordigt. Laten we nu kijken hoe we JSON naar een Java-object kunnen transformeren met behulp van de Jackson JSON-parser API.

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 {
		
		//lees JSON-bestandsgegevens naar String
		byte[] jsonData = Files.readAllBytes(Paths.get("employee.txt"));
		
		//maak een instantie van ObjectMapper aan
		ObjectMapper objectMapper = new ObjectMapper();
		
		//converteer JSON-string naar object
		Employee emp = objectMapper.readValue(jsonData, Employee.class);
		
		System.out.println("Employee Object\n"+emp);
		
		//converteer Object naar JSON-string
		Employee emp1 = createEmployee();
		//configureer de Object mapper voor mooi afdrukken
		objectMapper.configure(SerializationFeature.INDENT_OUTPUT, true);
		
		//schrijven naar de console, kan naar elke outputstream zoals een bestand schrijven
		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;
	}

}

Als je het bovenstaande programma uitvoert, krijg je de volgende uitvoer.

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
// Het afdrukken van dezelfde gegevens als het JSON-bestand hierboven.

com.fasterxml.jackson.databind.ObjectMapper is de belangrijkste klasse in de Jackson API die de methoden readValue() en writeValue() biedt om JSON naar Java Object en Java Object naar JSON te transformeren. De klasse ObjectMapper kan worden hergebruikt en we kunnen deze één keer initialiseren als Singleton-object. Er zijn zoveel overloaded versies van de methoden readValue() en writeValue() om te werken met byte array, bestand, input/output stream en Reader/Writer objecten.

Jackson JSON – JSON converteren naar Map

Soms hebben we een JSON-object zoals hieronder, in het bestand data.txt:

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

en we willen het converteren naar een Map en niet naar een Java-object met dezelfde eigenschappen en sleutels. We kunnen dit heel eenvoudig doen in de Jackson JSON API met twee methoden met de onderstaande code:


// JSON converteren naar Map

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


// Een andere manier

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

Zodra we het bovenstaande fragment uitvoeren, krijgen we de volgende uitvoer:

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

Jackson JSON – Een specifieke JSON-sleutel lezen

Soms hebben we JSON-gegevens en zijn we alleen geïnteresseerd in enkele waarden van de sleutels. In dat geval is het geen goed idee om de hele JSON naar een object te converteren. De Jackson JSON API biedt de mogelijkheid om JSON-gegevens als een boomstructuur te lezen, vergelijkbaar met een DOM-parser, waarmee we specifieke elementen van het JSON-object kunnen lezen. Onderstaande code geeft een voorbeeld van hoe je specifieke invoergegevens uit een JSON-bestand kunt lezen.

//lees JSON-bestandsgegevens naar String
byte[] jsonData = Files.readAllBytes(Paths.get("employee.txt"));

//maak een instantie van ObjectMapper aan
ObjectMapper objectMapper = new ObjectMapper();

//lees JSON als een 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());
}

We krijgen de volgende uitvoer wanneer we bovenstaande code uitvoeren.

id = 123
Phone No = 123456
Phone No = 987654

Jackson JSON – Bewerk JSON-document

De Jackson JSON Java API biedt handige methoden om sleutels aan JSON-gegevens toe te voegen, te bewerken en te verwijderen. Vervolgens kunnen we het opslaan als een nieuw JSON-bestand of naar een willekeurige stroom schrijven. Onderstaande code laat zien hoe dit eenvoudig kan worden gedaan.

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

ObjectMapper objectMapper = new ObjectMapper();

//maak JsonNode aan
JsonNode rootNode = objectMapper.readTree(jsonData);

//update JSON-gegevens
((ObjectNode) rootNode).put("id", 500);
//voeg nieuwe sleutel-waarde toe
((ObjectNode) rootNode).put("test", "test value");
//verwijder bestaande sleutel
((ObjectNode) rootNode).remove("role");
((ObjectNode) rootNode).remove("properties");
objectMapper.writeValue(new File("updated_emp.txt"), rootNode);

Als je bovenstaande code uitvoert en naar het nieuwe bestand zoekt, zul je merken dat het geen “role” en “properties” sleutels bevat. Je zult ook opmerken dat de waarde van “id” is bijgewerkt naar 500 en er een nieuwe sleutel “test” is toegevoegd aan het bestand updated_emp.txt.

Jackson JSON Streaming API Voorbeeld

Jackson JSON Java API biedt ook ondersteuning voor streaming die handig is bij het werken met grote JSON-gegevens omdat het het hele bestand leest als tokens en minder geheugen gebruikt. Het enige probleem met de streaming-API is dat we voor alle tokens moeten zorgen tijdens het parseren van de JSON-gegevens. Als we JSON-gegevens hebben als {“role”:“Manager”}, krijgen we de volgende tokens in volgorde – { (start object), “role” (sleutelnaam), “Manager” (sleutelwaarde) en } (eindobject). Een dubbele punt (:) is het scheidingsteken in JSON en wordt daarom niet beschouwd als een 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 {
		
		//maak JsonParser-object
		JsonParser jsonParser = new JsonFactory().createParser(new File("employee.txt"));
		
		//loop door de 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();
		//print werknemerobject
		System.out.println("Employee Object\n\n"+emp);
	}

	private static void parseJSON(JsonParser jsonParser, Employee emp,
			List phoneNums, boolean insidePropertiesObj) throws JsonParseException, IOException {
		
		//loop door de 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();
				//genest object, recursieve oproep
				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 is de Jackson JSON streaming API om JSON-gegevens te lezen, we gebruiken het om gegevens uit het bestand te lezen en vervolgens wordt de parseJSON() methode gebruikt om door de tokens te lopen en ze te verwerken om ons Java-object te maken. Let op dat de parseJSON() methode recursief wordt aangeroepen voor “adres” omdat het een genest object is in de JSON-gegevens. Voor het parseren van arrays lopen we door het JSON-document. We kunnen de klasse JsonGenerator gebruiken om JSON-gegevens te genereren met de streaming-API.

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"));
		//voor mooie opmaak
		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 is makkelijk te gebruiken in vergelijking met JsonParser. Dat is alles voor een snelle referentietutorial voor de Jackson JSON Parser Java API. Jackson JSON Java API is makkelijk te gebruiken en biedt veel opties voor het gemak van ontwikkelaars die met JSON-gegevens werken. Download het project vanaf onderstaande link en probeer ermee te experimenteren om meer opties over de Jackson Json API te ontdekken.

Download Jackson JSON Project

Referentie: Jackson GitHub Pagina

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