JSON serialization and deserialization using the Jackson library

If you think the content of this blog is helpful or inspiring to you, please follow my blog to get the latest technical articles and tutorials as soon as possible. At the same time, you are also welcome to leave a message in the comment area to share your thoughts and suggestions. Thank you for your support!

1. Preamble

In modern web development, JSON (JavaScript Object Notation) has become a widely used data format for front-end and back-end data transmission and storage. Java is an object-oriented programming language, and JSON is data in a key-value pair format, so in Java, you need to convert a Java object to a JSON string, or convert a JSON string to a Java object. This process is the serialization and deserialization of JSON.

For JSON serialization and deserialization in Java, there are many open source libraries to choose from, of which the Jackson library is one of the most popular. The Jackson library provides a wealth of features for flexible JSON serialization and deserialization with excellent performance.

This article will introduce the JSON serialization and deserialization of the Jackson library, including the serialization and deserialization of basic objects, collections, custom types, enumeration types, and Java time types. This article aims to let readers quickly understand and use the Jackson library for JSON serialization and deserialization.

2. What is JSON serialization and deserialization

JSON serialization is the process of converting a Java object into a JSON string. During the JSON serialization process, the properties of the Java object will be converted into key-value pairs of the JSON object. If the Java object contains other Java objects or collections, these nested objects will also be converted into nested JSON objects and JSON arrays.

JSON deserialization is the process of converting a JSON string into a Java object. During the JSON deserialization process, the key-value pairs of the JSON object will be converted to the properties of the Java object. If the JSON object contains other JSON objects or JSON arrays, these nested JSONs will also be converted to nested Java objects and Java collections.

Three, Jackson library introduction

The Jackson library is a Java-based JSON processing library, which provides a flexible JSON parser and JSON generator, which can easily convert Java objects and JSON data. The Jackson library is very simple to use and has excellent performance, so it is widely used in Java development.

The Jackson library has two core classes: ​ObjectMapper​and ​JsonNode​.

​​​​The class​ObjectMapper​ is the most important class in the Jackson library, which provides the conversion between serialization and deserialization of Java objects and JSON. ​ObjectMapper​Instances of the class

​​​​The class​JsonNode​ is an abstract class that represents a JSON node. The ​​​​class​JsonNode​ has multiple subclasses, such as ​ObjectNode​​, ​ArrayNode​​,​, ​ValueNode​etc. , corresponding to objects, arrays, and values ​​in JSON. The class​JsonNode​ provides convenience methods to read the value of a JSON node.

4. Basic type JSON serialization

1. Object serialization

The most basic way to convert a Java object to a JSON string is to ​ObjectMapper​use ​writeValueAsString​the method of the class. This method receives a Java object as a parameter and returns a JSON string.

For example:

ObjectMapper mapper = new ObjectMapper();
User user = new User("Tom", 20);
String json = mapper.writeValueAsString(user);

In the above code, we create an ​User​object and use ​ObjectMapper​the class to serialize it into a JSON string. ​User​The definition of the class

public class User {
    private String name;
    private int age;
    
    public User() {
    }
    
    public User(String name, int age) {
        this.name = name;
        this.age = age;
    }
    
    public String getName() {
        return name;
    }
    
    public void setName(String name) {
        this.name = name;
    }
    
    public int getAge() {
        return age;
    }
    
    public void setAge(int age) {
        this.age = age;
    }
}

The resulting JSON string is as follows:

{"name":"Tom","age":20}

2. Collection serialization

In addition to serializing a single Java object, the Jackson library also supports serializing Java collections, including ​List​​​, ​Set​​​​​and ​Map​​​etc. A Java collection can be serialized into a JSON string using the method of ​ObjectMapper​the class .​writeValueAsString​

ObjectMapper mapper = new ObjectMapper();
List<User> users = new ArrayList<>();
users.add(new User("Tom", 20));
users.add(new User("Jerry", 22));
String json = mapper.writeValueAsString(users);

In the above code, we create a ​List​collection and ​User​add two objects to the collection, and then use ​ObjectMapper​the class to serialize the collection into a JSON string.

The resulting JSON string is as follows:

[{"name":"Tom","age":20},{"name":"Jerry","age":22}]

3. Serialized enumeration type

In Java, an enumeration type is a common data type, which is usually used to represent a limited set of values. Serializing an enum type to a JSON string using the Jackson library is also a common operation. Here is the definition of a simple enumerated type:

public enum Gender {
    MALE, FEMALE
}

To serialize an enumeration type into a JSON string, we just need to add ​@JsonFormat​the annotation and specify the serialization format. For example, the following code will serialize an enum type using uppercase letters:

public class User {
    private String name;
    private int age;
    private Gender gender;
    
    // getters and setters
}

ObjectMapper mapper = new ObjectMapper();
mapper.enable(SerializationFeature.INDENT_OUTPUT);

User user = new User();
user.setName("Tom");
user.setAge(20);
user.setGender(Gender.MALE);

String json = mapper.writeValueAsString(user);
System.out.println(json);

The output is as follows:

{
  "name" : "Tom",
  "age" : 20,
  "gender" : "MALE"
}

In the above code, we first define a ​User​class , which contains a field of enumeration type ​gender​. We then use ​ObjectMapper​the class to ​User​serialize the object into a JSON string and print the result. As you can see, the value of the enumeration type has been serialized into a string type.

4. Serialize the Java time type

In practical applications, we often need to serialize Java time types into JSON strings for transmission to other systems or storage in databases. The Jackson library provides very convenient support for serializing Java 8 time types (such as ​java.time.LocalDateTime​) into JSON strings.

Here's an example of Java time type serialization using the Jackson library:

import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import com.fasterxml.jackson.databind.SerializationFeature;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;

public class JacksonDemo {
    public static void main(String[] args) throws Exception {
        ObjectMapper mapper = new ObjectMapper();
        mapper.registerModule(new JavaTimeModule());
        mapper.enable(SerializationFeature.INDENT_OUTPUT);
        
        LocalDateTime now = LocalDateTime.now(ZoneId.of("Asia/Shanghai"));
        String json = mapper.writeValueAsString(now);
        System.out.println(json);
        
        LocalDateTime parsed = mapper.readValue(json, LocalDateTime.class);
        System.out.println(parsed.format(DateTimeFormatter.ISO_LOCAL_DATE_TIME));
    }
}

In the above code, we first create a ​ObjectMapper​object and register ​JavaTimeModule​the module to support serialization of Java 8 time types. We then use ​LocalDateTime.now()​the method to get the current time and serialize it into a JSON string. Note that we use to ​ZoneId.of("Asia/Shanghai")​specify the time zone as Beijing time.

Next, we deserialize the JSON string into an object ​ObjectMapper​using the​​​​method. Finally, we format the deserialized object into ISO-8601 time format and print it out.​readValue()​​LocalDateTime​

The output is as follows:

"2022-02-23T14:25:23.845"
2022-02-23T14:25:23.845

As you can see, we successfully serialized the current time into a JSON string and restored the original time object when deserializing.

It should be noted that when serializing Java time types, the Jackson library uses the ISO-8601 time format by default. If you need to use other time formats, you can use the annotation to specify the time format. For example:@JsonFormat

@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss", timezone = "Asia/Shanghai")
private LocalDateTime startTime;

In the above code, we have specified the time format and time zone using ​@JsonFormat​the annotation . In this way, the Jackson library will use the specified time format for time serialization.

Five, basic type JSON deserialization

The basic way to convert a JSON string to a Java object is to ​ObjectMapper​use ​readValue​the method of the class. This method receives two parameters: a JSON string and a Java class, it will deserialize the JSON string into the specified Java class object.

1. Deserialize a single object

First, let's look at how to deserialize a JSON string into a single Java object. Suppose we have a JSON string representing an ​User​object :

{
    "name": "Tom",
    "age": 20
}

It can be deserialized into an object using the method of ​ObjectMapper​the class :​readValue​​User​

ObjectMapper mapper = new ObjectMapper();
String json = "{\"name\":\"Tom\",\"age\":20}";
User user = mapper.readValue(json, User.class);

In the above code, we create ​ObjectMapper​an instance of the class and deserialize the JSON string into ​User​an object.

2. Deserialize collection objects

In addition to deserializing a single Java object, the Jackson library also supports deserializing Java collections, including ​List​​​, ​Set​​and ​Map​​​etc. A JSON string can be deserialized into a Java collection using the method of ​ObjectMapper​the class .​readValue​

ObjectMapper mapper = new ObjectMapper();
String json = "[{\"name\":\"Tom\",\"age\":20},{\"name\":\"Jerry\",\"age\":22}]";
List<User> users = mapper.readValue(json, new TypeReference<List<User>>() {});

In the code above, we created a JSON string containing two ​User​Objects and deserialized it into ​List​a collection.

It should be noted that due to Java's generic erasure mechanism, you cannot directly ​List<User>​pass to ​readValue​the method, and you need to use ​TypeReference​the class to specify the collection type. ​​is​TypeReference​ a helper class provided by the Jackson library, which is used to obtain the type information of generic parameters.

3. Deserialize enumeration type

In Java, an enumeration type is a special data type that defines a fixed set of constants. In JSON data, strings are usually used to represent enumeration constants. Using the Jackson library can easily convert strings in JSON data to enumeration constants in Java.

The sample code is as follows:

First define an enumeration type:

public enum Gender {
    MALE,
    FEMALE
}

Then, suppose we have the following JSON data:

{
    "name": "Tom",
    "gender": "MALE"
}

We can convert strings in JSON data to enum constants in Java using the following code:

ObjectMapper mapper = new ObjectMapper();
String json = "{\"name\": \"Tom\", \"gender\": \"MALE\"}";
Map<String, Object> map = mapper.readValue(json, new TypeReference<Map<String, Object>>(){});
Gender gender = Gender.valueOf(map.get("gender").toString());

The above code first creates an object using the ObjectMapper class, and then parses the JSON data into a Map object. Finally, we can convert the strings in the Map to enum constants using the valueOf() method.

4. Deserialize Java time type

In Java, the time type is a very common data type, including Date, LocalDate, LocalTime, LocalDateTime, etc. In JSON data, time types are usually represented by strings. Using the Jackson library can easily convert strings in JSON data to time types in Java.

The sample code is as follows:

Suppose we have the following JSON data:

{
    "name": "Tom",
    "birthday": "2000-01-01"
}

We can use the following code to convert a string in JSON data to LocalDate type in Java:

ObjectMapper mapper = new ObjectMapper();
String json = "{\"name\": \"Tom\", \"birthday\": \"2000-01-01\"}";
Map<String, Object> map = mapper.readValue(json, new TypeReference<Map<String, Object>>(){});
LocalDate birthday = LocalDate.parse(map.get("birthday").toString());

The above code first creates an object using the ObjectMapper class, and then parses the JSON data into a Map object. Finally, we can use the parse() method to convert the strings in the Map to the LocalDate type. Deserialization of other time types is similar.

Six, custom serialization and deserialization

In some cases, the default serialization and deserialization behavior provided by the Jackson library may not meet the requirements, and custom serialization and deserialization rules are required. For example, when serializing ​User​an object , we want to serialize the age as a string type instead of the default integer type.

1. Custom serialization

To customize serialization rules, you need to create a class that implements ​JsonSerializer​the interface . ​​is​JsonSerializer​ an abstract class provided by the Jackson library, which is used to serialize Java objects into JSON strings.

Here is an example of serializing the age of an ​User​object as a string:

public class AgeToStringSerializer extends JsonSerializer<Integer> {
    @Override
    public void serialize(Integer value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
        gen.writeString(value.toString());
    }
}

In the above code, we defined a class ​AgeToStringSerializer​called , which inherits from ​JsonSerializer​the , and overrides ​serialize​the method . The method receives three parameters: the Java object to be serialized, ​JsonGenerator​the object , and an ​SerializerProvider​object that provides some information needed for serialization.

In ​serialize​the method , we ​value​convert the parameter to a string type and use ​gen.writeString​the method to write it ​JsonGenerator​into the object.

Next, we need ​User​to ​age​use ​@JsonSerialize​the annotation of the class to specify a custom ​AgeToStringSerializer​class for serialization:

public class User {
    private String name;
    @JsonSerialize(using = AgeToStringSerializer.class)
    private int age;
    private Address address;
    
    // ...
}

Then, we can use ​ObjectMapper​the class to ​User​serialize the object into a JSON string as before:

ObjectMapper mapper = new ObjectMapper();
User user = new User("Tom", 20, new Address("New York", "NY"));
String json = mapper.writeValueAsString(user);

The resulting JSON string is as follows:

{"name":"Tom","age":"20","address":{"city":"New York","state":"NY"}}

2. Custom deserialization

Similar to custom serialization, to customize deserialization rules, you need to create a class that implements ​JsonDeserializer​the interface . ​​is​JsonDeserializer​ an abstract class provided by the Jackson library, which is used to deserialize JSON strings into Java objects.

Here is an example that deserializes the age of ​User​an object from a string type to an integer type:

public class StringToAgeDeserializer extends JsonDeserializer<Integer> {
    @Override
    public Integer deserialize(JsonParser p, DeserializationContext ctxt) throws IOException, JsonProcessingException {
        String value = p.getValueAsString();
        return Integer.parseInt(value);
    }
}

In the above code, we have defined a class ​StringToAgeDeserializer​called which inherits from ​JsonDeserializer​the class and overrides ​deserialize​the method . The method receives two parameters: the ​JsonParser​object and a ​DeserializationContext​object that provides some information needed when deserializing.

In ​deserialize​the method , we first use ​p.getValueAsString​the method to obtain the value in the JSON string and convert it to a string type. We then use ​Integer.parseInt​the method to convert the value of type string to type integer and return the result.

Next, we need ​User​to ​age​use ​@JsonDeserialize​the annotation of the class to specify a custom ​StringToAgeDeserializer​class for deserialization:

public class User {
    private String name;
    @JsonSerialize(using = AgeToStringSerializer.class)
    @JsonDeserialize(using = StringToAgeDeserializer.class)
    private int age;
    private Address address;
    
    // ...
}

Then, we can deserialize the JSON string into an object using ​ObjectMapper​the class ​User​:

ObjectMapper mapper = new ObjectMapper();
String json = "{\"name\":\"Tom\",\"age\":\"20\",\"address\":{\"city\":\"New York\",\"state\":\"NY\"}}";
User user = mapper.readValue(json, User.class);

In the above code, we first define a JSON string, and ​ObjectMapper​use ​readValue​the method of the class to deserialize it into ​User​an object . Since the value of ​age​the field is a string type, it will be ​StringToAgeDeserializer​parsed using our custom class during deserialization. In the end, we will get an ​User​object whose ​age​field value is 20 of integer type.

5. The purpose and usage of common annotations

1. @JsonProperty

The @JsonProperty annotation is used to specify the name of the property in the Java object when it is serialized into JSON data. If this annotation is not used, the name of the property is used by default. When deserializing, this annotation is also used to specify which property in the Java object the name of the property in the JSON data corresponds to.

The sample code is as follows:

Suppose we have the following Java object:

public class Person {
    private String name;
    private int age;

    @JsonProperty("person_gender")
    private Gender gender;

    // getters and setters
}

We can use the @JsonProperty annotation to specify the name of the property, such as the gender property in the above code. When serializing this Java object into JSON data, the gender attribute will be serialized as a "person_gender" field.

ObjectMapper mapper = new ObjectMapper();
Person person = new Person();
person.setName("Tom");
person.setAge(20);
person.setGender(Gender.MALE);
String json = mapper.writeValueAsString(person);
System.out.println(json);

The output is:

{"name":"Tom","age":20,"person_gender":"MALE"}

2. @JsonFormat

The @JsonFormat annotation is used to specify the format of the date and time type in the Java object when it is serialized into JSON data. You can use this annotation to specify datetime format, time zone, etc.

The sample code is as follows:

Suppose we have the following Java object:

public class Person {
    private String name;

    @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd")
    private LocalDate birthday;

    // getters and setters
}

We can use the @JsonFormat annotation to specify the date and time format, such as the birthday attribute in the above code. When serializing this Java object into JSON data, the birthday property will be serialized into a date string in the format "yyyy-MM-dd".

ObjectMapper mapper = new ObjectMapper();
Person person = new Person();
person.setName("Tom");
person.setBirthday(LocalDate.of(2000, 1, 1));
String json = mapper.writeValueAsString(person);
System.out.println(json);

The output is:

{"name":"Tom","birthday":"2000-01-01"}

3. @JsonIgnore

The @JsonIgnore annotation is used to ignore the operation of a property in a Java object during serialization and deserialization. Attributes marked with this annotation will not be included when serialized into JSON data, nor will they be assigned values ​​when deserialized.

The sample code is as follows:

Suppose we have the following Java object:

public class Person {
    private String name;
    private int age;

    @JsonIgnore
    private Gender gender;

    // getters and setters
}

We can use the @JsonIgnore annotation to ignore the gender attribute, which will not be included when serializing to JSON data.

ObjectMapper mapper = new ObjectMapper();
Person person = new Person();
person.setName("Tom");
person.setAge(20);
person.setGender(Gender.MALE);
String json = mapper.writeValueAsString(person);
System.out.println(json);

The output is:

{"name":"Tom","age":20}

4. @JsonInclude

The @JsonInclude annotation is used to specify the conditions for certain properties in the Java object to be serialized into JSON data, for example, if the property is null or the default value, the property is not included.

The sample code is as follows:

Suppose we have the following Java object:

@JsonInclude(JsonInclude.Include.NON_NULL)
public class Person {
    private String name;
    private Integer age;
    private Gender gender;

    // getters and setters
}

We can use the @JsonInclude annotation to specify that when serializing to JSON data, if the age attribute is null, the attribute will not be included.

ObjectMapper mapper = new ObjectMapper();
Person person = new Person();
person.setName("Tom");
person.setAge(null);
person.setGender(Gender.MALE);
String json = mapper.writeValueAsString(person);
System.out.println(json);

The output is:

{"name":"Tom","gender":"MALE"}

5. @JsonTypeInfo

The @JsonTypeInfo annotation is used to specify the type information of Java objects during serialization and deserialization. This annotation can be used to specify the actual type of the subclass, and the JSON data can be correctly converted to the corresponding Java object during deserialization.

The sample code is as follows:

Suppose we have the following Java object:

@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "type")
@JsonSubTypes({
    @JsonSubTypes.Type(value = Dog.class, name = "dog"),
    @JsonSubTypes.Type(value = Cat.class, name = "cat")
})
public abstract class Animal {
    private String name;

    // getters and setters
}

public class Dog extends Animal {
    private String breed;

    // getters and setters
}

public class Cat extends Animal {
    private String color;

    // getters and setters
}

We can use the @JsonTypeInfo annotation to specify the subclass type information of the Animal object, and the JSON data can be correctly converted into the corresponding Java object during serialization and deserialization.

ObjectMapper mapper = new ObjectMapper();
Animal dog = new Dog();
dog.setName("Bobby");
((Dog) dog).setBreed("Bulldog");
String json = mapper.writeValueAsString(dog);
System.out.println(json);
Animal animal = mapper.readValue("{\"name\":\"Kitty\",\"type\":\"cat\",\"color\":\"white\"}", Animal.class);
System.out.println(animal.getClass().getName());
System.out.println(((Cat) animal).getColor());

The output is:

{"type":"dog","name":"Bobby","breed":"Bulldog"}
com.example.jackson.Cat
white

Summarize

This article describes how to use the Jackson library for JSON serialization and deserialization. We first learned about the basic concepts and usage of the Jackson library, and then explained in detail how to use ​ObjectMapper​classes for serialization and deserialization. In the process of serialization and deserialization, we also introduced how to deal with date and collection types, and explained how to customize serialization and deserialization rules.

Using the Jackson library for JSON serialization and deserialization is a common operation in Java development. The content introduced in this article covers most of the usage of the Jackson library. I believe readers have a preliminary understanding of the Jackson library. In actual development, you can choose different serialization and deserialization methods according to your needs to better meet business needs.

If you think the content of this blog is helpful or inspiring to you, please follow my blog to get the latest technical articles and tutorials as soon as possible. At the same time, you are also welcome to leave a message in the comment area to share your thoughts and suggestions. Thank you for your support!

Guess you like

Origin blog.csdn.net/bairo007/article/details/132520849