Jackson JSON Java解析器非常流行,也在Spring框架中使用。 Java JSON处理API不太用户友好,也不提供从Json到Java对象和反之间的自动转换功能。幸运的是,我们有一些备选的API可用于JSON处理。在上一篇文章中,我们学习了关于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-core 和 jackson-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();
//配置Object Mapper以进行漂亮的打印
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 对象转换为 JSON。ObjectMapper 类可以被重用,我们可以将其初始化为单例对象。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 流式 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 是 jackson json 流式 API 用于读取 json 数据,我们正在使用它从文件中读取数据,然后使用 parseJSON() 方法循环遍历标记并处理它们以创建我们的 Java 对象。请注意,对于“address”,parseJSON() 方法被递归调用,因为它是 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 的更多选项。
Source:
https://www.digitalocean.com/community/tutorials/jackson-json-java-parser-api-example-tutorial