杰瑞科技汇

Java JSON Jackson如何高效解析与序列化?

Of course! Here is a comprehensive guide to using JSON with Java, focusing on the most popular library: Jackson.

Java JSON Jackson如何高效解析与序列化?-图1
(图片来源网络,侵删)

We'll cover:

  1. What is JSON and why use it?
  2. What is Jackson?
  3. Setting up Jackson in your project (Maven/Gradle).
  4. Core Jackson Concepts: ObjectMapper, JsonParser, JsonGenerator.
  5. Serialization: Converting Java objects to JSON.
  6. Deserialization: Converting JSON to Java objects.
  7. Handling Complex Scenarios:
    • Polymorphic types (e.g., List, Map)
    • Customizing with Annotations (@JsonProperty, @JsonIgnore, etc.)
    • Handling Date/Time objects
    • Pretty-printing JSON
  8. Best Practices and Common Pitfalls.

What is JSON and Why Use It?

JSON (JavaScript Object Notation) is a lightweight, text-based data-interchange format. It's easy for humans to read and write, and easy for machines to parse and generate. It's the de-facto standard for web APIs and configuration files.

Why use it in Java?

  • Web APIs: Most modern REST APIs communicate by sending and receiving JSON data.
  • Configuration: JSON is a human-readable alternative to XML or .properties files.
  • Data Storage: Storing application data in a structured format.

What is Jackson?

Jackson is a high-performance, widely used Java library for processing JSON. It's the default JSON processor in the Spring Framework and many other popular Java libraries.

Java JSON Jackson如何高效解析与序列化?-图2
(图片来源网络,侵删)

Key Features:

  • High Performance: It's extremely fast and has a low memory footprint.
  • Rich Feature Set: Supports a huge range of JSON features.
  • Easy to Use: Provides a simple API for common tasks.
  • Excellent Documentation: Well-maintained and comprehensive.

Setting up Jackson

First, you need to add the Jackson dependencies to your project. You'll almost always need the core, databind, and annotations modules.

Using Maven (pom.xml)

<dependencies>
    <!-- The core databind module (includes core and annotations) -->
    <dependency>
        <groupId>com.fasterxml.jackson.core</groupId>
        <artifactId>jackson-databind</artifactId>
        <version>2.17.0</version> <!-- Use the latest version -->
    </dependency>
</dependencies>

Using Gradle (build.gradle)

implementation 'com.fasterxml.jackson.core:jackson-databind:2.17.0' // Use the latest version

Core Jackson Concepts

The central class in Jackson is ObjectMapper. It's the heart of the library and provides the main methods for reading and writing JSON.

import com.fasterxml.jackson.databind.ObjectMapper;
// Create a single, shared instance for your application
ObjectMapper objectMapper = new ObjectMapper();

Serialization: Java Object to JSON

Serialization is the process of converting a Java object into a JSON string.

Java JSON Jackson如何高效解析与序列化?-图3
(图片来源网络,侵删)

Let's start with a simple POJO (Plain Old Java Object).

Example POJO: User.java

import java.util.Date;
public class User {
    private String name;
    private int age;
    private String email;
    private boolean isActive;
    private Date registrationDate;
    // Default constructor is required for deserialization
    public User() {}
    // Getters and Setters
    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; }
    public String getEmail() { return email; }
    public void setEmail(String email) { this.email = email; }
    public boolean isActive() { return isActive; }
    public void setActive(boolean active) { isActive = active; }
    public Date getRegistrationDate() { return registrationDate; }
    public void setRegistrationDate(Date registrationDate) { this.registrationDate = registrationDate; }
    @Override
    public String toString() {
        return "User{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", email='" + email + '\'' +
                ", isActive=" + isActive +
                ", registrationDate=" + registrationDate +
                '}';
    }
}

Serialization Code

import com.fasterxml.jackson.databind.ObjectMapper;
import java.util.Date;
public class SerializationExample {
    public static void main(String[] args) throws Exception {
        // 1. Create an instance of ObjectMapper
        ObjectMapper objectMapper = new ObjectMapper();
        // 2. Create a Java object
        User user = new User();
        user.setName("John Doe");
        user.setAge(30);
        user.setEmail("john.doe@example.com");
        user.setActive(true);
        user.setRegistrationDate(new Date());
        // 3. Serialize the object to a JSON string
        // The writeValueAsString() method is the most common way.
        String jsonString = objectMapper.writeValueAsString(user);
        // 4. Print the result
        System.out.println(jsonString);
    }
}

Output:

{"name":"John Doe","age":30,"email":"john.doe@example.com","isActive":true,"registrationDate":1703123456789}

Deserialization: JSON to Java Object

Deserialization is the reverse process: converting a JSON string into a Java object.

Deserialization Code

import com.fasterxml.jackson.databind.ObjectMapper;
public class DeserializationExample {
    public static void main(String[] args) throws Exception {
        // 1. Create an instance of ObjectMapper
        ObjectMapper objectMapper = new ObjectMapper();
        // 2. JSON string to be converted
        String jsonString = "{\"name\":\"Jane Doe\",\"age\":28,\"email\":\"jane.doe@example.com\",\"isActive\":false,\"registrationDate\":1703123456789}";
        // 3. Deserialize the JSON string into a User object
        // The readValue() method requires the JSON string and the target class type.
        User user = objectMapper.readValue(jsonString, User.class);
        // 4. Print the Java object
        System.out.println(user);
    }
}

Output:

User{name='Jane Doe', age=28, email='jane.doe@example.com', isActive=false, registrationDate=Wed Dec 20 10:30:56 UTC 2025}

Handling Complex Scenarios

A. Polymorphic Types (Lists, Maps)

ObjectMapper can handle collections and maps directly.

Example: Serializing a List<User>

import com.fasterxml.jackson.databind.ObjectMapper;
import java.util.Arrays;
import java.util.List;
public class ListSerializationExample {
    public static void main(String[] args) throws Exception {
        ObjectMapper objectMapper = new ObjectMapper();
        User user1 = new User(); // ... set properties
        user1.setName("Alice");
        user1.setAge(25);
        User user2 = new User(); // ... set properties
        user2.setName("Bob");
        user2.setAge(40);
        List<User> userList = Arrays.asList(user1, user2);
        // Serialize the list directly
        String jsonString = objectMapper.writeValueAsString(userList);
        System.out.println(jsonString);
    }
}

Output:

[{"name":"Alice","age":25,"email":null,"isActive":false,"registrationDate":null},{"name":"Bob","age":40,"email":null,"isActive":false,"registrationDate":null}]

Example: Deserializing into a List<User>

import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.util.List;
public class ListDeserializationExample {
    public static void main(String[] args) throws Exception {
        ObjectMapper objectMapper = new ObjectMapper();
        String jsonArrayString = "[{\"name\":\"Alice\",\"age\":25},{\"name\":\"Bob\",\"age\":40}]";
        // Use TypeReference to specify the generic type
        List<User> userList = objectMapper.readValue(jsonArrayString, new TypeReference<List<User>>() {});
        userList.forEach(System.out::println);
    }
}

Note: When deserializing into a generic type like List<T> or Map<K, V>, you must use objectMapper.readValue(jsonString, new TypeReference<YourGenericType>() {}); because Java type erasure prevents objectMapper.readValue(jsonString, List.class) from working correctly.

B. Customizing with Annotations

Jackson provides powerful annotations to control the serialization/deserialization process.

Annotation Description
@JsonProperty("json_name") Maps a field to a specific JSON property name.
@JsonIgnore Excludes a field from being serialized or deserialized.
@JsonIgnoreProperties(ignoreUnknown = true) On a class, tells Jackson to ignore any properties in the JSON that don't have a corresponding field in the Java class.
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd") Formats a date/time field into a specific string pattern.

Example: User.java with Annotations

import com.fasterxml.jackson.annotation.*;
import java.util.Date;
@JsonInclude(JsonInclude.Include.NON_NULL) // Don't include null values in JSON
@JsonIgnoreProperties(ignoreUnknown = true) // Ignore unknown JSON properties
public class User {
    @JsonProperty("full_name")
    private String name;
    private int age;
    @JsonIgnore // Never serialize/deserialize this field
    private String internalId;
    @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "dd-MM-yyyy HH:mm:ss")
    private Date registrationDate;
    // Getters and Setters...
}

C. Pretty-Printing JSON

To make the output human-readable (e.g., for debugging), enable pretty-printing.

import com.fasterxml.jackson.databind.ObjectMapper;
public class PrettyPrintExample {
    public static void main(String[] args) throws Exception {
        ObjectMapper objectMapper = new ObjectMapper();
        // Enable pretty printing
        objectMapper.enable(SerializationFeature.INDENT_OUTPUT);
        User user = new User();
        user.setName("John Doe");
        user.setAge(30);
        String jsonString = objectMapper.writeValueAsString(user);
        System.out.println(jsonString);
    }
}

Output:

{
  "name" : "John Doe",
  "age" : 30,
  "email" : null,
  "isActive" : false,
  "registrationDate" : null
}

Best Practices and Common Pitfalls

  1. Reuse ObjectMapper: Creating an ObjectMapper is an expensive operation. Create one instance per application (or per thread if necessary) and reuse it. It's thread-safe for read operations.

  2. Handle Exceptions: Jackson operations (writeValueAsString, readValue) throw IOException. Always wrap them in a try-catch block.

    try {
        String json = objectMapper.writeValueAsString(myObject);
    } catch (JsonProcessingException e) {
        // Handle the exception, e.g., log it
        e.printStackTrace();
    }
  3. Use @JsonIgnoreProperties: When consuming external APIs, you can't control the JSON schema. Use @JsonIgnoreProperties(ignoreUnknown = true) on your POJO to prevent your application from crashing if the JSON contains extra fields.

  4. Immutable Objects: For better thread safety and design, you might use immutable objects (with final fields). Jackson can handle these using a constructor or a static "factory method". Use @JsonCreator and @JsonProperty on the constructor/factory method.

    public final class ImmutableUser {
        private final String name;
        private final int age;
        @JsonCreator // Marks this method as the factory for deserialization
        public ImmutableUser(@JsonProperty("name") String name, @JsonProperty("age") int age) {
            this.name = name;
            this.age = age;
        }
        // Getters...
    }
  5. Circular References: If two objects reference each other (e.g., User has a List<Post> and each Post has a User author), Jackson will run into an infinite loop and throw a StackOverflowError. To fix this, use @JsonIgnore on one side of the relationship or use @JsonManagedReference and @JsonBackReference.

分享:
扫描分享到社交APP
上一篇
下一篇