1. Introduction
1.绪论
JavaScript Object Notation, or JSON, has gained a lot of popularity as a data interchange format in recent years. Jsoniter is a new JSON parsing library aimed at offering a more flexible and more performant JSON parsing than the other available parsers.
近年来,JavaScript Object Notation(即JSON)作为一种数据交换格式获得了很大的欢迎。Jsoniter是一个新的JSON解析库,旨在提供比其他可用解析器更灵活、更高性能的JSON解析。
In this tutorial, we’ll see how to parse JSON objects using the Jsoniter library for Java.
在本教程中,我们将看到如何使用Java的Jsoniter库来解析JSON对象。
2. Dependencies
2.依赖性
The latest version of Jsoniter can be found from the Maven Central repository.
Jsoniter的最新版本可以从Maven Central仓库找到。
Let’s start by adding the dependencies to the pom.xml:
让我们先把依赖项添加到pom.xml中。
<dependency>
<groupId>com.jsoniter<groupId>
<artifactId>jsoniter</artifactId>
<version>0.9.23</version>
</dependency>
Similarly, we can add the dependency to our build.gradle file:
同样地,我们可以将该依赖性添加到我们的build.gradle文件中。
compile group: 'com.jsoniter', name: 'jsoniter', version: '0.9.23'
3. JSON Parsing Using Jsoniter
3.使用Jsoniter进行JSON解析
Jsoniter provides 3 APIs to parse JSON documents:
Jsoniter提供了3个API来解析JSON文档。
- Bind API
- Any API
- Iterator API
Let’s look into each of the above APIs.
让我们来看看上述每个API的情况。
3.1. JSON Parsing Using the Bind API
3.1.使用Bind API进行JSON解析
The bind API uses the traditional way of binding the JSON document to Java classes.
绑定API使用传统方式将JSON文档绑定到Java类。
Let’s consider the JSON document with student details:
让我们考虑一下包含学生详细信息的JSON文档。
{"id":1,"name":{"firstName":"Joe","surname":"Blogg"}}
Let’s now define the Student and Name schema classes to represent the above JSON:
现在让我们定义Student 和Name schema类来表示上述JSON。
public class Student {
private int id;
private Name name;
// standard setters and getters
}
public class Name {
private String firstName;
private String surname;
// standard setters and getters
}
De-serializing the JSON to a Java object using the bind API is very simple. We use the deserialize method of JsonIterator:
使用bind API将JSON反序列化为一个Java对象是非常简单的。我们使用JsonIterator的deserialize方法。
@Test
public void whenParsedUsingBindAPI_thenConvertedToJavaObjectCorrectly() {
String input = "{\"id\":1,\"name\":{\"firstName\":\"Joe\",\"surname\":\"Blogg\"}}";
Student student = JsonIterator.deserialize(input, Student.class);
assertThat(student.getId()).isEqualTo(1);
assertThat(student.getName().getFirstName()).isEqualTo("Joe");
assertThat(student.getName().getSurname()).isEqualTo("Blogg");
}
The Student schema class declares the id to be of int datatype. However, what if the JSON that we receive contains a String value for the id instead of a number? For example:
Student模式类声明id为intdatatype。然而,如果我们收到的JSON包含String值的id,而不是一个数字,怎么办?比如说。
{"id":"1","name":{"firstName":"Joe","surname":"Blogg"}}
Notice how the id in the JSON is a string value “1” this time. Jsoniter provides Maybe decoders to deal with this scenario.
注意JSON中的id这次是一个字符串值“1”。Jsoniter提供了Maybe解码器来处理这种情况。
3.2. Maybe Decoders
3.2.Maybe解码器
Jsoniter’s Maybe decoders come in handy when the datatype of a JSON element is fuzzy. The datatype for the student.id field is fuzzy — it can either be a String or an int. To handle this, we need to annotate the id field in our schema class using the MaybeStringIntDecoder:
当JSON元素的数据类型模糊时,Jsoniter的Maybe解码器派上用场。student.id字段的数据类型是模糊的–它可以是一个String或一个int。为了处理这个问题,我们需要使用MaybeStringIntDecoder在我们的模式类中对id字段进行注释。
public class Student {
@JsonProperty(decoder = MaybeStringIntDecoder.class)
private int id;
private Name name;
// standard setters and getters
}
We can now parse the JSON even when the id value is a String:
现在我们可以解析JSON,即使id值是String。
@Test
public void givenTypeInJsonFuzzy_whenFieldIsMaybeDecoded_thenFieldParsedCorrectly() {
String input = "{\"id\":\"1\",\"name\":{\"firstName\":\"Joe\",\"surname\":\"Blogg\"}}";
Student student = JsonIterator.deserialize(input, Student.class);
assertThat(student.getId()).isEqualTo(1);
}
Similarly, Jsoniter offers other decoders such as MaybeStringLongDecoder and MaybeEmptyArrayDecoder.
类似地,Jsoniter还提供其他解码器,如MaybeStringLongDecoder和MaybeEmptyArrayDecoder。
Let’s now imagine that we were expecting to receive a JSON document with the Student details but we receive the following document instead:
现在让我们想象一下,我们期望收到一个包含Student详细信息的JSON文档,但我们收到的却是以下文档。
{"error":404,"description":"Student record not found"}
What happened here? We were expecting a success response with Student data but we received an error response. This is a very common scenario but how would we handle this?
这里发生了什么?我们期待一个带有Student数据的成功响应,但我们收到一个error响应。这是一个非常常见的情况,但我们如何处理这种情况呢?
One way is to perform a null check to see if we received an error response before extracting the Student data. However, the null checks can lead to some hard-to-read code, and the problem is made worse if we have a multi-level nested JSON.
一种方法是在提取Student数据之前,执行null检查,看我们是否收到错误响应。然而,null检查会导致一些难以阅读的代码,如果我们有一个多级嵌套的JSON,这个问题就会变得更糟。
Jsoniter’s parsing using the Any API comes to the rescue.
Jsoniter使用Any API的解析来拯救。
3.3. JSON Parsing Using the Any API
3.3.使用Any API进行JSON解析
When the JSON structure itself is dynamic, we can use Jsoniter’s Any API that provides a schema-less parsing of the JSON. This works similarly to parsing the JSON into a Map<String, Object>.
当JSON结构本身是动态的,我们可以使用Jsoniter的Any API,它提供了一个无模式的JSON解析。这与将JSON解析为Map<String, Object>的工作方式类似。
Let’s parse the Student JSON as before but using the Any API this time:
让我们像以前一样解析Student JSON,但这次使用Any API。
@Test
public void whenParsedUsingAnyAPI_thenFieldValueCanBeExtractedUsingTheFieldName() {
String input = "{\"id\":1,\"name\":{\"firstName\":\"Joe\",\"surname\":\"Blogg\"}}";
Any any = JsonIterator.deserialize(input);
assertThat(any.toInt("id")).isEqualTo(1);
assertThat(any.toString("name", "firstName")).isEqualTo("Joe");
assertThat(any.toString("name", "surname")).isEqualTo("Blogg");
}
Let’s understand this example. First, we use the JsonIterator.deserialize(..) to parse the JSON. However, we do not specify a schema class in this instance. The result is of type Any.
让我们来理解这个例子。首先,我们使用JsonIterator.deserialize(.)来解析JSON。然而,我们没有在这个实例中指定一个模式类。结果的类型是Any。
Next, we read the field values using the field names. We read the “id” field value using the Any.toInt method. The toInt method converts the “id” value to an integer. Similarly, we read the “name.firstName” and “name.surname” field values as string values using the toString method.
接下来,我们使用字段名读取字段的值。我们使用Any.toInt方法读取 “id “字段值。toInt方法将 “id “值转换为一个整数。同样,我们使用toString方法将 “name.firstName “和 “name.surname “字段的值读为字符串值。
Using the Any API, we can also check if an element is present in the JSON. We can do this by looking up the element and then inspecting the valueType of the lookup result. The valueType will be INVALID when the element is not present in the JSON.
使用Any API,我们也可以检查一个元素是否存在于JSON中。我们可以通过查找该元素,然后检查查找结果的valueType来实现。当该元素不存在于JSON中时,valueType将是INVALID。
For example:
比如说。
@Test
public void whenParsedUsingAnyAPI_thenFieldValueTypeIsCorrect() {
String input = "{\"id\":1,\"name\":{\"firstName\":\"Joe\",\"surname\":\"Blogg\"}}";
Any any = JsonIterator.deserialize(input);
assertThat(any.get("id").valueType()).isEqualTo(ValueType.NUMBER);
assertThat(any.get("name").valueType()).isEqualTo(ValueType.OBJECT);
assertThat(any.get("error").valueType()).isEqualTo(ValueType.INVALID);
}
The “id” and “name” fields are present in the JSON and hence their valueType is NUMBER and OBJECT respectively. However, the JSON input does not have an element by the name “error” and so the valueType is INVALID.
在JSON中存在 “id “和 “name “字段,因此它们的valueType分别为NUMBER和OBJECT。然而,JSON输入没有一个名为 “error “的元素,所以valueType是INVALID。
Going back to the scenario mentioned at the end of the previous section, we need to detect whether the JSON input we received is a success or an error response. We can check if we received an error response by inspecting the valueType of the “error” element:
回到上一节末尾提到的场景,我们需要检测我们收到的JSON输入是成功还是错误响应。我们可以通过检查 “error “元素的valueType来检查我们是否收到一个错误响应。
String input = "{\"error\":404,\"description\":\"Student record not found\"}";
Any response = JsonIterator.deserialize(input);
if (response.get("error").valueType() != ValueType.INVALID) {
return "Error!! Error code is " + response.toInt("error");
}
return "Success!! Student id is " + response.toInt("id");
When run, the above code will return “Error!! Error code is 404”.
当运行时,上述代码将返回“错误!错误代码是404”。
Next, we’ll look at using the Iterator API to parse JSON documents.
接下来,我们将看看如何使用Iterator API来解析JSON文档。
3.4. JSON Parsing Using the Iterator API
3.4.使用迭代器API对JSON进行解析
If we wish to perform the binding manually, we can use Jsoniter’s Iterator API. Let’s consider the JSON:
如果我们希望手动执行绑定,我们可以使用Jsoniter的Iterator API。让我们考虑JSON。
{"firstName":"Joe","surname":"Blogg"}
We’ll use the Name schema class that we used earlier to parse the JSON using the Iterator API:
我们将使用之前使用的Name模式类,使用Iterator API来解析JSON。
@Test
public void whenParsedUsingIteratorAPI_thenFieldValuesExtractedCorrectly() throws Exception {
Name name = new Name();
String input = "{\"firstName\":\"Joe\",\"surname\":\"Blogg\"}";
JsonIterator iterator = JsonIterator.parse(input);
for (String field = iterator.readObject(); field != null; field = iterator.readObject()) {
switch (field) {
case "firstName":
if (iterator.whatIsNext() == ValueType.STRING) {
name.setFirstName(iterator.readString());
}
continue;
case "surname":
if (iterator.whatIsNext() == ValueType.STRING) {
name.setSurname(iterator.readString());
}
continue;
default:
iterator.skip();
}
}
assertThat(name.getFirstName()).isEqualTo("Joe");
assertThat(name.getSurname()).isEqualTo("Blogg");
}
Let’s understand the above example. First, we parse the JSON document as an iterator. We use the resulting JsonIterator instance to iterate over the JSON elements:
让我们来理解上面的例子。首先,我们解析JSON文档作为一个迭代器。我们使用产生的JsonIterator实例来遍历JSON元素。
- We start by invoking the readObject method which returns the next field name (or a null if the end of the document has been reached).
- If the field name is not of interest to us, we skip the JSON element by using the skip method. Otherwise, we inspect the data type of the element by using the whatIsNext method. Invoking the whatIsNext method is not mandatory but is useful when the datatype of the field is unknown to us.
- Finally, we extract the value of the JSON element using the readString method.
4. Conclusion
4.总结
In this article, we discussed the various approaches offered by Jsoniter for parsing the JSON documents as Java objects.
在这篇文章中,我们讨论了Jsoniter提供的将JSON文档解析为Java对象的各种方法。
First, we looked at the standard way of parsing a JSON document using a schema class.
首先,我们看了使用模式类来解析JSON文档的标准方式。
Next, we looked at handling fuzzy data types and the dynamic structures when parsing JSON documents using the Maybe decoders and Any datatype, respectively.
接下来,我们分别使用Maybe解码器和Any数据类型解析JSON文档时,研究了处理模糊数据类型和动态结构。
Finally, we looked at the Iterator API for binding the JSON manually to a Java object.
最后,我们看了Iterator API,将JSON手动绑定到一个Java对象。
As always the source code for the examples used in this article is available over on GitHub.
像往常一样,本文中使用的例子的源代码可在GitHub上获得。