在开发项目时,一个常见的应用场景是将内存中的对象转换为一个JSON字符串,或者将一个JSON字符串转换为一个内存中的对象。上述的这两个过程被称为数据序列化(Data Serialization)和数据反序列化(Data Deserialization)。
在Java第三方代码库中,json-simple,GSON,JSONP和Jackson都是非常流行的JSON代码库。本文将重点介绍Jackson库的使用方法,因为Jackson库有以下诸多优点。
我们将在四篇文章中介绍Jackson库的使用方法。此篇文章首先介绍Jackson库的内部结构和各部件的功能,并讲解Jackson底层部件的工作原理。我们将在下一篇重点介绍Jackson的编程接口和使用方法,并使用示例展示几种JSON字符串转换的不同应用场景。第三篇和第四篇会分别介绍XML文档和YAML文档的生成和解析方法。
Jackson库的核心内容分为三个模块。
以上三个模块之间的依赖关系如下。
图一 Jackson模块依赖图
Streaming API提供了一套底层接口用于解析和生成JSON字符串。我们将在下面的两个小节中分别介绍JSON字符串解析和生成的使用方法。
如果使用Maven管理项目,需要将如下依赖关系加入项目的pom.xml文件中。
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>2.11.1</version>
</dependency>
如果使用Gradle管理项目,需要将如下依赖加入项目的build.gradle文件中。
repositories {
mavenCentral()
}
dependencies {
implementation 'com.fasterxml.jackson.core:jackson-core:2.11.1'
}
在底层接口中,JsonParser对象用于解析JSON字符串。在解析的过程中,JsonParser对象会通过nextToken()函数不断地向上层逻辑返回解析的Token,直到isClose()函数返回true为止。上述的Token实际上代表着JSON字符串中的关键字段或者分隔符。
如下面的代码所示。在JsonParserExample类的main()函数中,我们定义了一个JSON字符串。该字符串包含两个键值对(name和age)。name的值是字符串Adam;age的值是整数18。
随后,我们创建了一个JsonFactory对象,再由这个factory对象创建一个JsonParser对象。此时,这个JsonParser对象已经准备好开始解析JSON字符串了。最后,我们使用一个while循环,遍历JSON字符串中所有的token。nextToken()函数返回当前的Token。当所有的Token都被读取之后,nextToken()函数返回null。我们在循环中,每获得一个token,则打印这个token的类型。
import java.io.IOException;
import com.fasterxml.jackson.core.JsonParseException;
import com.fasterxml.jackson.core.JsonFactory;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonToken;
public class JsonParserExample {
public static void main(String[] args) {
String aJson = "{ \"name\" : \"Adam\", \"age\" : 18 }";
try {
JsonFactory factory = new JsonFactory();
JsonParser parser = factory.createParser(aJson);
// 使用parser对象遍历所有的token
while(true){
JsonToken token = parser.nextToken();
if (token == null)
break;
// 打印Token的内容
System.out.println("token = " + token);
}
} catch (IOException ex) {
System.out.println(ex.getMessage());
}
}
}
如下是该程序输出的Token的类型。
token = START_OBJECT
token = FIELD_NAME
token = VALUE_STRING
token = FIELD_NAME
token = VALUE_NUMBER_INT
token = END_OBJECT
这些Token与JSON字符串中内容的对照如下图所示。
图二 Token与JSON字符串内容对照图
在获得一个JsonToken对象之后,可以通过判断JsonToken对象的类型来获取Token对应的名称和值。如下面的代码所示,如果当前的Token是FIELD_NAME的话,我们可以调用getCurrentName()方法来获取名称。然后再调用nextToken()前进到下一个Token。这个Token应该对应的是值。所以,可以根据值的类型,分别使用getValueAsString()或者getValueAsInt()获取值。
import java.io.IOException;
import com.fasterxml.jackson.core.JsonParseException;
import com.fasterxml.jackson.core.JsonFactory;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonToken;
public class JsonParserExample {
public static void main(String[] args) {
String aJson = "{ \"name\" : \"Adam\", \"age\" : 18 }";
try {
JsonFactory factory = new JsonFactory();
JsonParser parser = factory.createParser(aJson);
while(true){
JsonToken jsonToken = parser.nextToken();
if (jsonToken == null)
break;
if(JsonToken.FIELD_NAME.equals(jsonToken)){
String fieldName = parser.getCurrentName();
jsonToken = parser.nextToken();
if("name".equals(fieldName)){
System.out.println(fieldName + "=" + parser.getValueAsString());
} else if ("age".equals(fieldName)){
System.out.println(fieldName + "=" + parser.getValueAsInt());
}
}
}
} catch (IOException ex) {
System.out.println(ex.getMessage());
}
}
}
程序输出的结果为:
name=Adam
age=18
JSON文档的生成是通过使用JsonGenerator完成的。为了生成上述相同的JSON文档,我们首先创建一个JsonFactory对象,并由这个factory对象,创建一个JsonGenerator对象。然后,向JsonGenerator对象添加Token和键值对。writeStartObject()和writeEndObject()方法分别向generator对象添加左花括号和右花括号。writeStringField()和writeNumberField()方法分别添加键值对。最后,在关闭generator对象后,JSON字符串会被写入jsonBuffer的对象中,最后将生成的JSON字符串打印出来。
import java.io.IOException;
import java.io.ByteArrayOutputStream;
import com.fasterxml.jackson.core.JsonParseException;
import com.fasterxml.jackson.core.JsonFactory;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonEncoding;
public class JsonGeneratorExample {
public static void main(String[] args) {
try {
ByteArrayOutputStream jsonBuffer = new ByteArrayOutputStream();
JsonFactory factory = new JsonFactory();
JsonGenerator generator = factory.createGenerator(jsonBuffer, JsonEncoding.UTF8);
generator.writeStartObject();
generator.writeStringField("name", "Adam");
generator.writeNumberField("age", 18);
generator.writeEndObject();
generator.close();
System.out.println(jsonBuffer.toString("utf-8"));
} catch (IOException ex) {
System.out.println(ex.getMessage());
}
}
}
程序的输出为一个紧凑格式的JSON字符串,如下所示。
{"name":"Adam","age":18}
本章介绍了Jackson的内部结构和Stream API的使用方法。我们将在下一章介绍Jackson库的另外两个模块:Data Binding和Annotation。
注册用户登陆后可留言