Appearance
Using JSON
Earlier, we discussed the XML data format. XML is feature-rich but comes with cumbersome tags and complex formatting. Its usage on the web is declining, being increasingly replaced by the JSON data structure.
JSON stands for JavaScript Object Notation. It removes all executable JavaScript code, retaining only the object format of JavaScript. A typical JSON example is as follows:
json
{
"id": 1,
"name": "Core Java",
"author": {
"firstName": "Abc",
"lastName": "Xyz"
},
"isbn": "1234567",
"tags": ["Java", "Network"]
}
As a data transmission format, JSON has several significant advantages:
- JSON only allows UTF-8 encoding, avoiding encoding issues;
- JSON only permits the use of double quotes for keys, with special characters escaped using
\
, resulting in a simple format; - Browsers have built-in JSON support. If data is sent to the browser in JSON format, it can be directly processed with JavaScript.
Therefore, JSON is suitable for representing hierarchical structures because of its simple format, supporting only the following data types:
- Key-Value Pairs:
{"key": value}
- Arrays:
[1, 2, 3]
- Strings:
"abc"
- Numbers (integers and floating-point):
12.34
- Boolean Values:
true
orfalse
- Null Values:
null
Browsers directly support reading and writing JSON using JavaScript:
javascript
// JSON string to JavaScript object:
jsObj = JSON.parse(jsonStr);
// JavaScript object to JSON string:
jsonStr = JSON.stringify(jsObj);
Thus, when developing web applications, using JSON for data transmission is very convenient on the browser side. Since JSON is inherently suitable for JavaScript processing, the vast majority of REST APIs choose JSON as their data transmission format.
Now the question arises: How can Java read and write JSON?
In Java, there is also a standard JSR 353 API for JSON. However, as we saw earlier with XML, it is best if we can directly convert between XML and JavaBeans. Similarly, if we can directly convert between JSON and JavaBeans, it becomes much simpler to use.
Common third-party libraries for parsing JSON include:
- Jackson
- GSON
- JSON-lib
- ...
Notice that Jackson, the library we mentioned earlier for parsing XML, can also parse JSON! Therefore, we only need to include the following Maven dependency:
xml
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.12.0</version>
</dependency>
Then, define the JavaBean and use the following code to parse a JSON file:
java
InputStream input = Main.class.getResourceAsStream("/book.json");
ObjectMapper mapper = new ObjectMapper();
// Ignore unknown JavaBean properties during deserialization:
mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
Book book = mapper.readValue(input, Book.class);
The core code involves creating an ObjectMapper
object. Disabling the DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES
feature ensures that parsing does not throw an error if the JavaBean lacks certain properties present in the JSON.
Converting JSON to a JavaBean is called deserialization. Conversely, converting a JavaBean to JSON is called serialization. To achieve serialization from a JavaBean to JSON, only one line of code is needed:
java
String json = mapper.writeValueAsString(book);
To parse certain JSON values into specific Java objects, such as LocalDate
, it is entirely possible. For example:
json
{
"name": "Core Java",
"pubDate": "2016-09-01"
}
To parse into:
java
public class Book {
public String name;
public LocalDate pubDate;
}
Simply include the standard JSR 310 data type module in Maven:
xml
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-jsr310</artifactId>
<version>2.12.0</version>
</dependency>
Then, when creating the ObjectMapper
, register a new JavaTimeModule
:
java
ObjectMapper mapper = new ObjectMapper().registerModule(new JavaTimeModule());
Sometimes, the built-in parsing rules and extended parsing rules do not meet our requirements. In such cases, custom parsing can be implemented.
For example, suppose the isbn
field in the Book
class is a BigInteger
:
java
public class Book {
public String name;
public BigInteger isbn;
}
However, the JSON data does not follow the standard integer format:
json
{
"name": "Core Java",
"isbn": "978-7-111-54742-6"
}
Direct parsing would certainly result in an error. At this point, we need to create a custom IsbnDeserializer
to parse strings containing non-numeric characters:
java
public class IsbnDeserializer extends JsonDeserializer<BigInteger> {
@Override
public BigInteger deserialize(JsonParser p, DeserializationContext ctxt) throws IOException, JsonProcessingException {
// Read the original JSON string content:
String s = p.getValueAsString();
if (s != null) {
try {
return new BigInteger(s.replace("-", ""));
} catch (NumberFormatException e) {
throw new JsonParseException(p, s, e);
}
}
return null;
}
}
Then, use annotations in the Book
class to specify the custom deserializer:
java
public class Book {
public String name;
// Use the custom IsbnDeserializer when deserializing the isbn field:
@JsonDeserialize(using = IsbnDeserializer.class)
public BigInteger isbn;
}
Similarly, to customize serialization, you would create a custom IsbnSerializer
and annotate the Book
class with @JsonSerialize(using = ...)
.
Deserialization
During deserialization, Jackson requires that Java classes have a default no-argument constructor. Otherwise, it cannot instantiate the class directly. For classes with parameterized constructors, ensure that a no-argument constructor is also provided to facilitate deserialization.
For enum
fields, Jackson treats them as String
types. For example:
java
public class Book {
public DayOfWeek start = DayOfWeek.MONDAY;
}
Serializes to:
json
{
"start": "MONDAY"
}
For record
types, Jackson automatically detects the parameterized constructor and matches it with the JSON keys, allowing direct deserialization. Support for record
types requires Jackson version 2.12.0 or higher.
Exercise
Use Jackson to parse JSON.
Summary
- JSON is a lightweight data representation format commonly used in web applications;
- Jackson facilitates the conversion between JavaBeans and JSON;
- Modules can be used to extend the data types that Jackson can handle;
- Custom
JsonSerializer
andJsonDeserializer
can be implemented to tailor the serialization and deserialization processes.