Jackson JSON Java 解析器 API 範例教程

Jackson JSON Java 解析器非常流行,也在 Spring 框架中使用。 Java JSON 处理 API 不太用户友好,也不提供从 Json 自动转换为 Java 对象以及反之的功能。幸运的是,我们有一些可供 JSON 处理使用的替代 API。在上一篇文章中,我们了解了 Google Gson API 并看到了它的使用方法有多简单。

Jackson JSON Java 解析器

要在我们的项目中使用 Jackson JSON Java API,我们可以将其添加到项目构建路径中,或者如果您正在使用 Maven,则可以添加以下依赖项。

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

jackson-databind jar 取決於 jackson-corejackson-annotations 庫,因此如果您直接將它們添加到構建路徑中,請確保添加所有三個,否則您將收到運行時錯誤。Jackson JSON 解析器 API 提供了將 JSON 轉換為 POJO 對象的簡單方法,並支持從 JSON 數據輕鬆轉換為 Map。Jackson 還支持泛型,並直接將它們從 JSON 轉換為對象。

Jackson JSON 示例

對於我們的 JSON 到 POJO/Java 對象轉換示例,我們將使用一個具有嵌套對象和數組的複雜示例。我們將在 Java 對象中使用數組、列表和 Map 進行轉換。我們的複雜 json 存儲在一個名為 employee.txt 的文件中,結構如下:

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

我們有以下 Java 類與 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();
	}
}

Address 類對應於根 json 數據中的內部對象。

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 是表示根 json 對象的 Java bean。現在讓我們看看如何使用 Jackson JSON 解析器 API 將 JSON 轉換為 Java 對象。

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 {
		
		// 將 json 文件數據讀取為字符串
		byte[] jsonData = Files.readAllBytes(Paths.get("employee.txt"));
		
		// 創建 ObjectMapper 實例
		ObjectMapper objectMapper = new ObjectMapper();
		
		// 將 json 字符串轉換為對象
		Employee emp = objectMapper.readValue(jsonData, Employee.class);
		
		System.out.println("Employee Object\n"+emp);
		
		// 將對象轉換為 json 字符串
		Employee emp1 = createEmployee();
		// 配置對象映射器以進行漂亮的打印
		objectMapper.configure(SerializationFeature.INDENT_OUTPUT, true);
		
		// 寫入到控制台,可以寫入到任何輸出流,如文件
		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;
	}

}

當我們運行上面的程序時,您將獲得以下輸出。

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
//列印與上述 JSON 檔案數據相同

com.fasterxml.jackson.databind.ObjectMapper是Jackson API中最重要的類別,提供readValue()和writeValue()方法,將JSON轉換為Java物件並將Java物件轉換為JSONObjectMapper類別可以被重複使用,我們可以初始化它一次作為Singleton對象。readValue()和writeValue()方法有許多重載版本,可用於處理位元組陣列、文件、輸入/輸出流和Reader/Writer對象。

Jackson JSON – 將JSON轉換為Map

有時我們有一個像下面的JSON對象,在data.txt文件中:

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

我們想將其轉換為Map,而不是具有相同屬性和鍵的Java對象。在Jackson JSON API中,我們可以使用以下代碼輕鬆完成這兩種方法:

//將json轉換為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);

//另一種方式
myMap = objectMapper.readValue(mapData, new TypeReference>() {});
System.out.println("Map using TypeReference: "+myMap);

執行上述片段後,我們獲得以下輸出:

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

Jackson JSON – 讀取特定的JSON鍵

有时我们有json数据,我们只对其中几个键的值感兴趣,因此在这种情况下将整个JSON转换为对象不是一个好主意。Jackson JSON API提供了将json数据作为DOM解析器读取的选项,我们可以通过它读取JSON对象的特定元素。下面的代码提供了从json文件中读取特定条目的代码片段。

//将json文件数据读取为字符串
byte[] jsonData = Files.readAllBytes(Paths.get("employee.txt"));

//创建ObjectMapper实例
ObjectMapper objectMapper = new ObjectMapper();

//像DOM解析器一样读取JSON
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());
}

执行上述代码片段时,我们会得到以下输出。

id = 123
Phone No = 123456
Phone No = 987654

Jackson JSON – 编辑JSON文档

Jackson JSON Java API提供了一些有用的方法来向JSON数据中添加、编辑和删除键,然后我们可以将其保存为新的json文件或将其写入任何流中。下面的代码演示了如何轻松实现这一点。

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

ObjectMapper objectMapper = new ObjectMapper();

//创建JsonNode
JsonNode rootNode = objectMapper.readTree(jsonData);

//更新JSON数据
((ObjectNode) rootNode).put("id", 500);
//添加新的键值对
((ObjectNode) rootNode).put("test", "test value");
//删除现有键
((ObjectNode) rootNode).remove("role");
((ObjectNode) rootNode).remove("properties");
objectMapper.writeValue(new File("updated_emp.txt"), rootNode);

如果您执行上述代码并查看新文件,您会注意到它不再包含”role”和”properties”键。您还会注意到”id”的值已更新为500,并且在updated_emp.txt文件中添加了一个新的键”test”。

Jackson JSON Streaming API範例

Jackson JSON Java API也提供了流式支援,對於處理大型JSON數據非常有幫助,因為它將整個文件讀取為標記並使用較少的內存。流式API的唯一問題是我們需要在解析JSON數據時注意所有標記。如果我們的JSON數據為{“role”:”Manager”},則按順序會得到以下標記:{(開始對象),”role”(鍵名稱),”Manager”(鍵值)和}(結束對象)。冒號(:)是JSON中的分隔符,因此不被視為標記。

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 {
		
		//創建JsonParser對象
		JsonParser jsonParser = new JsonFactory().createParser(new File("employee.txt"));
		
		//循環遍歷標記
		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();
		//打印員工對象
		System.out.println("Employee Object\n\n"+emp);
	}

	private static void parseJSON(JsonParser jsonParser, Employee emp,
			List phoneNums, boolean insidePropertiesObj) throws JsonParseException, IOException {
		
		//循環遍歷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();
				//嵌套對象,遞歸調用
				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是用於讀取JSON數據的Jackson JSON流式API,我們正在使用它從文件中讀取數據,然後使用parseJSON()方法循環遍歷標記並處理它們以創建我們的java對象。請注意,parseJSON()方法對於“address”是遞歸調用,因為它是JSON數據中的嵌套對象。對於解析數組,我們正在循環遍歷json文檔。我們可以使用JsonGenerator類生成流API的JSON數據。

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"));
		//用於美化打印
		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 使用起來比 JsonParser 容易。這就是關於 Jackson JSON 解析器 Java API 的快速參考教程。Jackson JSON Java API 使用方便,為開發人員使用 JSON 數據提供了很多選項。從下面的鏈接下載項目,並嘗試使用它來探索更多關於 Jackson Json API 的選項。

下載 Jackson JSON 項目

參考資料:Jackson GitHub 頁面

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