程序员scholar 程序员scholar
首页
  • Java 基础

    • JavaSE
    • JavaIO
    • JavaAPI速查
  • Java 高级

    • JUC
    • JVM
    • Java新特性
    • 设计模式
  • Web 开发

    • Servlet
    • Java网络编程
  • Web 标准

    • HTML
    • CSS
    • JavaScript
  • 前端框架

    • Vue2
    • Vue3
    • Vue3 + TS
    • 微信小程序
    • uni-app
  • 工具与库

    • jQuery
    • Ajax
    • Axios
    • Webpack
    • Vuex
    • WebSocket
    • 第三方登录
  • 后端与语言扩展

    • ES6
    • Typescript
    • node.js
  • Element-UI
  • Apache ECharts
  • 数据结构
  • HTTP协议
  • HTTPS协议
  • 计算机网络
  • Linux常用命令
  • Windows常用命令
  • SQL数据库

    • MySQL
    • MySQL速查
  • NoSQL数据库

    • Redis
    • ElasticSearch
  • 数据库

    • MyBatis
    • MyBatis-Plus
  • 消息中间件

    • RabbitMQ
  • 服务器

    • Nginx
  • Spring框架

    • Spring6
    • SpringMVC
    • SpringBoot
    • SpringSecurity
  • SpringCould微服务

    • SpringCloud基础
    • 微服务之DDD架构思想
  • 日常必备

    • 开发常用工具包
    • Hutoll工具包
    • IDEA常用配置
    • 开发笔记
    • 日常记录
    • 项目部署
    • 网站导航
    • 产品学习
    • 英语学习
  • 代码管理

    • Maven
    • Git教程
    • Git小乌龟教程
  • 运维工具

    • Docker
    • Jenkins
    • Kubernetes
  • 算法笔记

    • 算法思想
    • 刷题笔记
  • 面试问题常见

    • 十大经典排序算法
    • 面试常见问题集锦
关于
GitHub (opens new window)
首页
  • Java 基础

    • JavaSE
    • JavaIO
    • JavaAPI速查
  • Java 高级

    • JUC
    • JVM
    • Java新特性
    • 设计模式
  • Web 开发

    • Servlet
    • Java网络编程
  • Web 标准

    • HTML
    • CSS
    • JavaScript
  • 前端框架

    • Vue2
    • Vue3
    • Vue3 + TS
    • 微信小程序
    • uni-app
  • 工具与库

    • jQuery
    • Ajax
    • Axios
    • Webpack
    • Vuex
    • WebSocket
    • 第三方登录
  • 后端与语言扩展

    • ES6
    • Typescript
    • node.js
  • Element-UI
  • Apache ECharts
  • 数据结构
  • HTTP协议
  • HTTPS协议
  • 计算机网络
  • Linux常用命令
  • Windows常用命令
  • SQL数据库

    • MySQL
    • MySQL速查
  • NoSQL数据库

    • Redis
    • ElasticSearch
  • 数据库

    • MyBatis
    • MyBatis-Plus
  • 消息中间件

    • RabbitMQ
  • 服务器

    • Nginx
  • Spring框架

    • Spring6
    • SpringMVC
    • SpringBoot
    • SpringSecurity
  • SpringCould微服务

    • SpringCloud基础
    • 微服务之DDD架构思想
  • 日常必备

    • 开发常用工具包
    • Hutoll工具包
    • IDEA常用配置
    • 开发笔记
    • 日常记录
    • 项目部署
    • 网站导航
    • 产品学习
    • 英语学习
  • 代码管理

    • Maven
    • Git教程
    • Git小乌龟教程
  • 运维工具

    • Docker
    • Jenkins
    • Kubernetes
  • 算法笔记

    • 算法思想
    • 刷题笔记
  • 面试问题常见

    • 十大经典排序算法
    • 面试常见问题集锦
关于
GitHub (opens new window)
npm

(进入注册为作者充电)

  • Java常用开发工具包

    • Jackson(JSON处理库)
    • FastJson2(JSON处理库)
    • Gson(JSON处理库)
      • 一、Gson 简介与环境配置
        • 1.1 Gson 核心特性
        • 1.2 添加 Gson 依赖
      • 二、基础操作:Java 对象与 JSON 的互转
        • 2.1 Java 对象序列化为 JSON 字符串
        • 2.2 JSON 字符串反序列化为 Java 对象
      • 三、高级应用:复杂 JSON 数据处理
        • 3.1 嵌套 JSON 结构解析 (使用 JsonObject)
        • 3.2 JSON 数组处理 (使用 JsonArray)
      • 四、集合类型处理:JSON 与 Java 集合互转
        • 4.1 JSON 数组字符串转换为 List 集合
        • 4.2 JSON 对象字符串转换为 Map 集合
        • 4.3 Java 集合序列化为 JSON 字符串
      • 五、自定义序列化与反序列化
        • 5.1 自定义日期格式 (GsonBuilder)
        • 5.2 忽略特定字段
        • 5.3 指定 JSON 字段名 (@SerializedName)
      • 六、Gson 高级配置选项 (GsonBuilder)
        • 6.1 格式化 JSON 输出 (setPrettyPrinting)
        • 6.2 处理 null 值 (serializeNulls)
        • 6.3 其他常用 GsonBuilder 配置
      • 七、实战应用场景
        • 7.1 在 Spring Boot 中集成 Gson
        • 7.2 处理动态或未知结构的 JSON (树模型)
    • BeanUtils(对象复制工具)
    • MapStruct(对象转换工具)
    • Guava(开发工具包)
    • ThreadLocal(本地线程变量)
    • SLF4j(日志框架)
    • Lombok (注解插件)
  • 开发工具包
  • Java常用开发工具包
scholar
2024-08-20
目录

Gson(JSON处理库)

# Gson(JSON处理库)

前言

Gson (也写作 google-gson) 是由 Google 开发并开源的一款功能强大、性能优异且易于使用的 Java 库,专门用于实现 Java 对象与 JSON (JavaScript Object Notation) 数据格式之间的相互转换(序列化与反序列化)。凭借其简洁的 API 设计、对复杂对象模型的良好支持以及无需强制注解的灵活性,Gson 在 Java 社区得到了广泛应用,尤其是在 Android 开发和众多后端服务(包括 Spring Boot 应用)中,是处理 JSON 数据的热门选择之一。本文将深入探讨 Gson 的核心功能、高级用法及实战技巧。

# 一、Gson 简介与环境配置

# 1.1 Gson 核心特性

Gson 之所以备受青睐,主要得益于以下几个核心优势:

  • 易用性: 提供极其简单的 toJson() 和 fromJson() 方法即可完成大部分转换任务。
  • 无需注解: 对于标准 Java Bean,Gson 无需任何注解即可进行序列化和反序列化。当然,它也提供了 @SerializedName、@Expose 等注解进行更细粒度的控制。
  • 复杂对象支持: 能够自动处理任意复杂的 Java 对象,包括深层嵌套的对象、泛型集合等。
  • 泛型支持: 通过 TypeToken 提供了对泛型类型的完美支持,解决了 Java 泛型擦除带来的问题。
  • 自定义能力: 允许通过 GsonBuilder 定制序列化/反序列化的各种行为,如日期格式、字段命名策略、null 值处理、排除特定字段等,甚至可以注册自定义的 TypeAdapter 实现完全控制。
  • 性能良好: 在大多数场景下,Gson 提供了令人满意的性能表现。
  • JSON 树模型: 提供了 JsonElement、JsonObject、JsonArray 等类,允许以类似 DOM 的方式操作 JSON 结构,适合处理动态或未知结构的 JSON 数据。

# 1.2 添加 Gson 依赖

要在项目中使用 Gson,首先需要将其库文件添加到项目的依赖中。

Maven 项目依赖配置:

在你的 pom.xml 文件中,添加以下 <dependency>:

<dependency>
    <groupId>com.google.code.gson</groupId>
    <artifactId>gson</artifactId>
    <!-- 建议查阅 Gson 官方仓库获取最新的稳定版本 -->
    <version>2.9.0</version>
</dependency>
1
2
3
4
5
6

注意: 2.9.0 是编写本文时的一个常用稳定版本。请访问 Gson 的 Maven Central (opens new window) 或 GitHub Releases (opens new window) 页面查找并使用最新的推荐版本(例如 2.10.1 或更高)。

Gradle 项目依赖配置:

在你的 build.gradle (或 build.gradle.kts) 文件中,添加以下依赖:

// build.gradle (Groovy DSL)
implementation 'com.google.code.gson:gson:2.9.0' // 同样,请使用最新稳定版本

// build.gradle.kts (Kotlin DSL)
// implementation("com.google.code.gson:gson:2.9.0")
1
2
3
4
5

# 二、基础操作:Java 对象与 JSON 的互转

Gson 的核心功能在于 Java 对象和 JSON 字符串之间的双向转换。

# 2.1 Java 对象序列化为 JSON 字符串

序列化是将 Java 对象的状态转换为 JSON 字符串的过程。

import com.google.gson.Gson;

/**
 * Gson 示例:将 Java 对象序列化为 JSON 字符串
 */
public class GsonObjectToJsonExample {
    public static void main(String[] args) {
        // 1. 创建 Gson 实例
        // Gson 实例是线程安全的,可以重用
        Gson gson = new Gson();

        // 2. 创建一个需要被序列化的 Java 对象 (POJO)
        User user = new User("张三", 25);

        // 3. 调用 toJson() 方法将 Java 对象转换为 JSON 字符串
        String jsonString = gson.toJson(user);

        // 4. 输出生成的 JSON 字符串
        System.out.println("Java 对象序列化为 JSON 字符串: " + jsonString);
        // 预期输出: {"name":"张三","age":25}
    }
}

/**
 * 用户 POJO 类 (Plain Old Java Object)
 * Gson 默认会序列化所有非 transient、非 static 的字段
 */
class User {
    private String name; // 用户姓名
    private int age;     // 用户年龄
    // private transient String password; // 使用 transient 关键字可以阻止 Gson 序列化该字段

    // Gson 反序列化通常需要一个无参构造函数 (可以是 private)
    // 如果没有无参构造函数,Gson 会尝试使用 Unsafe 创建实例 (可能不稳定)
    // public User() {}

    // 用于创建对象的构造函数
    public User(String name, int age) {
        this.name = name;
        this.age = age;
    }

    // Gson 序列化/反序列化不强制要求 Getter/Setter 方法,
    // 它默认可以通过反射直接访问字段 (即使是 private)。
    // 但提供 Getter/Setter 是良好的面向对象实践。
    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; }

    @Override
    public String toString() {
        return "User{" + "name='" + name + '\'' + ", age=" + age + '}';
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55

# 2.2 JSON 字符串反序列化为 Java 对象

反序列化是将 JSON 字符串解析并填充到 Java 对象中的过程。

import com.google.gson.Gson;
import com.google.gson.JsonSyntaxException; // 用于捕获 JSON 格式错误

/**
 * Gson 示例:将 JSON 字符串反序列化为 Java 对象
 */
public class GsonJsonToObjectExample {
    public static void main(String[] args) {
        // 1. 创建 Gson 实例
        Gson gson = new Gson();

        // 2. 准备一个待解析的 JSON 字符串
        String jsonString = "{\"name\":\"李四\",\"age\":30, \"email\":\"lisi@example.com\"}"; // 包含 email 字段

        try {
            // 3. 调用 fromJson() 方法将 JSON 字符串转换为指定类型的 Java 对象
            // 第一个参数是 JSON 字符串或 Reader
            // 第二个参数是目标 Java 类的 Class 对象
            User user = gson.fromJson(jsonString, User.class);

            // 4. 输出反序列化后 Java 对象的信息
            // 注意:即使 JSON 中有 email 字段,但 User 类没有对应字段,Gson 默认会忽略它
            System.out.println("JSON 字符串成功反序列化为 User 对象:");
            System.out.println("- 姓名: " + user.getName());
            System.out.println("- 年龄: " + user.getAge());
            // 预期输出:
            // JSON 字符串成功反序列化为 User 对象:
            // - 姓名: 李四
            // - 年龄: 30

        } catch (JsonSyntaxException e) {
            // 处理可能发生的 JSON 格式错误
            System.err.println("JSON 解析错误: " + e.getMessage());
        }

        // 示例:处理格式错误的 JSON
        String invalidJson = "{\"name\":\"王五\", age:invalid}"; // age 值格式错误
        try {
            gson.fromJson(invalidJson, User.class);
        } catch (JsonSyntaxException e) {
            System.err.println("解析无效 JSON 时捕获到异常: " + e.getMessage());
        }
    }
    // User 类定义同上一个示例
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45

核心 API:

  • Gson(): 创建一个具有默认配置的 Gson 实例。
  • GsonBuilder(): 用于创建具有自定义配置的 Gson 实例(将在后续章节介绍)。
  • toJson(Object src): 将指定的 Java 对象序列化为其 JSON 表示形式(字符串)。
  • fromJson(String json, Class<T> classOfT): 将指定的 JSON 字符串反序列化为指定 Class 类型的对象。
  • fromJson(Reader json, Class<T> classOfT): 从 Reader 读取并反序列化。
  • fromJson(String json, Type typeOfT): 用于反序列化为泛型类型(如 List<User>),将在集合处理部分介绍。

# 三、高级应用:复杂 JSON 数据处理

当 JSON 结构复杂、嵌套层次深,或结构不固定时,可以使用 Gson 提供的树模型 (JsonElement, JsonObject, JsonArray) 进行更灵活的操作。

# 3.1 嵌套 JSON 结构解析 (使用 JsonObject)

JsonObject 允许像操作 Map 一样访问 JSON 对象的属性。

import com.google.gson.Gson;
import com.google.gson.JsonObject;
import com.google.gson.JsonElement; // 引入 JsonElement
import com.google.gson.JsonSyntaxException;

/**
 * Gson 示例:使用 JsonObject 解析嵌套 JSON 结构
 */
public class GsonNestedJsonExample {
    public static void main(String[] args) {
        // 1. 创建 Gson 实例
        Gson gson = new Gson();

        // 2. 准备一个包含嵌套对象的 JSON 字符串
        String jsonString = "{"
            + "\"name\": \"赵六\","
            + "\"age\": 22,"
            + "\"active\": true,"
            + "\"address\": {" // address 是一个嵌套的 JSON 对象
                + "\"city\": \"上海\","
                + "\"district\": \"浦东新区\","
                + "\"zip\": \"200120\""
            + "},"
            + "\"scores\": [95, 88, 76]" // 包含一个 JSON 数组
        + "}";

        try {
            // 3. 将 JSON 字符串解析为 JsonObject
            // 使用 fromJson() 并指定目标类型为 JsonObject.class
            JsonObject jsonObject = gson.fromJson(jsonString, JsonObject.class);

            // 4. 访问顶层基本类型的属性
            // 使用 get() 方法获取 JsonElement,然后使用 asString, asInt, asBoolean 等获取具体类型的值
            String name = jsonObject.get("name").getAsString();
            int age = jsonObject.get("age").getAsInt();
            boolean active = jsonObject.get("active").getAsBoolean();

            System.out.println("基本信息:");
            System.out.println("- 姓名: " + name);
            System.out.println("- 年龄: " + age);
            System.out.println("- 是否活跃: " + active);

            // 5. 访问嵌套的 JSON 对象 (address)
            // 使用 get() 获取代表 address 的 JsonElement,然后使用 getAsJsonObject() 转换为 JsonObject
            JsonObject addressObject = jsonObject.getAsJsonObject("address"); // 更简洁的写法
            // 或者: JsonObject addressObject = jsonObject.get("address").getAsJsonObject();

            if (addressObject != null) { // 推荐检查是否为 null
                String city = addressObject.get("city").getAsString();
                String district = addressObject.get("district").getAsString();
                String zip = addressObject.get("zip").getAsString();
                System.out.println("地址信息:");
                System.out.println("- 城市: " + city);
                System.out.println("- 区县: " + district);
                System.out.println("- 邮编: " + zip);
            }

            // 6. 检查属性是否存在 (推荐使用 has() 方法)
            if (jsonObject.has("email")) {
                System.out.println("- 邮箱: " + jsonObject.get("email").getAsString());
            } else {
                System.out.println("- 邮箱: 未提供");
            }

            // 7. 安全地获取属性 (处理 null 或不存在的情况)
            // 先检查是否存在,或获取 JsonElement 后检查是否为 JsonNull
            JsonElement ageElement = jsonObject.get("age");
            if (ageElement != null && !ageElement.isJsonNull()) {
                // 处理 age...
            }
            // Gson 的 getAsXXX 通常在 null 或类型不匹配时抛异常,不如先判断或使用 POJO 映射安全

        } catch (JsonSyntaxException e) {
            System.err.println("JSON 解析错误: " + e.getMessage());
        } catch (NullPointerException | IllegalStateException e) {
            // 处理获取属性或类型转换时可能发生的错误
            System.err.println("访问 JSON 属性时出错: " + e.getMessage());
        }
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80

输出结果:

基本信息:
- 姓名: 赵六
- 年龄: 22
- 是否活跃: true
地址信息:
- 城市: 上海
- 区县: 浦东新区
- 邮编: 200120
- 邮箱: 未提供
1
2
3
4
5
6
7
8
9

# 3.2 JSON 数组处理 (使用 JsonArray)

JsonArray 允许像操作 List 一样遍历和访问 JSON 数组的元素。

import com.google.gson.Gson;
import com.google.gson.JsonArray;
import com.google.gson.JsonObject; // 需要引入 JsonObject
import com.google.gson.JsonElement; // 需要引入 JsonElement
import com.google.gson.JsonSyntaxException;

/**
 * Gson 示例:使用 JsonArray 处理 JSON 数组
 */
public class GsonArrayExample {
    public static void main(String[] args) {
        // 1. 创建 Gson 实例
        Gson gson = new Gson();

        // 2. 准备一个 JSON 数组字符串,包含多个用户对象
        String jsonString = "["
            + "{\"name\":\"张三\",\"age\":25,\"city\":\"北京\"},"
            + "{\"name\":\"李四\",\"age\":30,\"city\":\"上海\"},"
            + "{\"name\":\"王五\",\"age\":28,\"city\":\"广州\"}"
        + "]";

        try {
            // 3. 将 JSON 字符串解析为 JsonArray
            JsonArray jsonArray = gson.fromJson(jsonString, JsonArray.class);
            // 或者使用 JsonParser (更通用,自动识别根是对象还是数组)
            // JsonArray jsonArray = JsonParser.parseString(jsonString).getAsJsonArray();

            System.out.println("JSON 数组包含 " + jsonArray.size() + " 个元素。");

            // 4. 遍历 JsonArray
            System.out.println("\n遍历 JSON 数组:");

            // 方法一:使用增强 for-each 循环 (元素类型是 JsonElement)
            for (JsonElement element : jsonArray) {
                // 需要将 JsonElement 转换为 JsonObject 来访问其属性
                if (element.isJsonObject()) { // 检查元素是否为 JSON 对象
                    JsonObject userObject = element.getAsJsonObject();
                    String name = userObject.get("name").getAsString();
                    int age = userObject.get("age").getAsInt();
                    String city = userObject.get("city").getAsString();
                    System.out.println("  - 姓名: " + name + ", 年龄: " + age + ", 城市: " + city);
                }
            }

            // 方法二:使用索引访问 (类似 List)
            if (jsonArray.size() > 1) {
                JsonObject secondUser = jsonArray.get(1).getAsJsonObject(); // 获取第二个元素
                System.out.println("\n访问第二个用户:");
                System.out.println("  - 姓名: " + secondUser.get("name").getAsString());
            }

            // 方法三:使用 Java 8 Stream API
            System.out.println("\n使用 Stream API 过滤和输出:");
            jsonArray.asList().stream() // JsonArray 可以通过 asList() 转为 List<JsonElement>
                .map(JsonElement::getAsJsonObject) // 转换为 JsonObject 流
                .filter(obj -> obj.get("age").getAsInt() > 28) // 过滤年龄大于 28 的用户
                .forEach(user -> System.out.println("  - 年龄大于 28 的用户: " + user.get("name").getAsString()));

        } catch (JsonSyntaxException e) {
            System.err.println("JSON 解析错误: " + e.getMessage());
        } catch (IllegalStateException e) {
            System.err.println("访问 JSON 元素时出错(例如,尝试将非对象元素作为对象访问): " + e.getMessage());
        }
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65

输出结果:

JSON 数组包含 3 个元素。

遍历 JSON 数组:
  - 姓名: 张三, 年龄: 25, 城市: 北京
  - 姓名: 李四, 年龄: 30, 城市: 上海
  - 姓名: 王五, 年龄: 28, 城市: 广州

访问第二个用户:
  - 姓名: 李四

使用 Stream API 过滤和输出:
  - 年龄大于 28 的用户: 李四
1
2
3
4
5
6
7
8
9
10
11
12

树模型 API 核心:

  • JsonParser.parseString(String json): (推荐) 静态方法,将 JSON 字符串解析为 JsonElement (可能是 JsonObject, JsonArray, JsonPrimitive, JsonNull)。

  • gson.fromJson(String json, Class<T> classOfT): 也可以用来解析为 JsonObject.class 或 JsonArray.class。

  • JsonElement: JSON 树模型的基类。

    • isJsonObject(), getAsJsonObject(): 判断并转换为 JsonObject。
    • isJsonArray(), getAsJsonArray(): 判断并转换为 JsonArray。
    • isJsonPrimitive(), getAsJsonPrimitive(): 判断并转换为 JsonPrimitive (表示字符串、数字、布尔值)。
    • isJsonNull(): 判断是否为 JSON null。
  • JsonObject:

    • get(String memberName): 获取指定名称的 JsonElement。
    • has(String memberName): 检查是否存在指定名称的成员。
    • getAsJsonObject(String memberName), getAsJsonArray(String memberName): 获取并直接转换为 JsonObject 或 JsonArray。
    • add(String property, JsonElement value): 添加或替换属性。
    • remove(String property): 移除属性。
  • JsonArray:

    • get(int index): 获取指定索引的 JsonElement。
    • size(): 获取数组大小。
    • add(JsonElement element): 添加元素。
    • remove(int index): 移除元素。
    • asList(): 将 JsonArray 转换为 List<JsonElement> (Java 8 Stream API 友好)。
  • JsonPrimitive:

    • getAsString(), getAsInt(), getAsDouble(), getAsBoolean(), getAsBigDecimal(), getAsBigInteger(), getAsNumber(): 获取原始值。

使用树模型可以非常灵活地处理结构未知或动态变化的 JSON,但代码通常比直接映射 POJO 更繁琐。

# 四、集合类型处理:JSON 与 Java 集合互转

Gson 对 Java 的集合类型(如 List, Map)提供了良好的支持,尤其擅长处理泛型集合。

# 4.1 JSON 数组字符串转换为 List 集合

处理 JSON 数组到 Java List 的转换,特别是当 List 包含泛型对象(如 List<User>)时,需要使用 TypeToken 来解决 Java 泛型擦除的问题。

import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken; // 引入 TypeToken
import com.google.gson.JsonSyntaxException;

import java.lang.reflect.Type; // 引入 Type
import java.util.List;
import java.util.ArrayList; // 可以是 ArrayList 或其他 List 实现

/**
 * Gson 示例:将 JSON 数组字符串反序列化为 Java List 集合
 */
public class GsonJsonToListExample {
    public static void main(String[] args) {
        // 1. 创建 Gson 实例
        Gson gson = new Gson();

        // 2. 准备一个包含多个用户对象的 JSON 数组字符串
        String jsonString = "["
            + "{\"name\":\"张三\",\"age\":25},"
            + "{\"name\":\"李四\",\"age\":30},"
            + "{\"name\":\"王五\",\"age\":28}"
        + "]";

        try {
            // 3. 创建目标泛型类型的 Type 对象
            // 使用 TypeToken 的匿名子类来捕获完整的泛型类型信息 (List<User>)
            Type userListType = new TypeToken<ArrayList<User>>() {}.getType();
            // 注意:这里使用 ArrayList<User> 或 List<User> 都可以,
            // Gson 会根据 JSON 结构创建合适的 List 实现 (通常是 ArrayList)。

            // 4. 调用 fromJson() 方法,传入 JSON 字符串和 Type 对象
            List<User> userList = gson.fromJson(jsonString, userListType);

            // 5. 遍历并输出反序列化后的 List<User> 集合
            System.out.println("JSON 数组成功反序列化为 List<User>:");
            if (userList != null) {
                userList.forEach(user ->
                    System.out.println("  - 姓名: " + user.getName() + ", 年龄: " + user.getAge())
                );
            }
            // 预期输出:
            // 姓名: 张三, 年龄: 25
            // 姓名: 李四, 年龄: 30
            // 姓名: 王五, 年龄: 28

            // 示例:反序列化基本类型的 List
            String numbersJson = "[10, 20, 30, 40, 50]";
            Type integerListType = new TypeToken<List<Integer>>() {}.getType();
            List<Integer> numbers = gson.fromJson(numbersJson, integerListType);
            System.out.println("\nJSON 数组反序列化为 List<Integer>:");
            System.out.println("  " + numbers); // 输出: [10, 20, 30, 40, 50]

        } catch (JsonSyntaxException e) {
            System.err.println("JSON 解析错误: " + e.getMessage());
        }
    }
    // User 类定义同上
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58

关键点: TypeToken 通过创建一个带有泛型参数的匿名子类,利用 Java 的类型系统在运行时保留了完整的泛型信息(如 List<User>),从而让 Gson 知道应该将 JSON 数组中的每个对象反序列化为什么类型。

# 4.2 JSON 对象字符串转换为 Map 集合

将 JSON 对象转换为 Java Map 同样需要使用 TypeToken 来指定键和值的泛型类型。

import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import com.google.gson.JsonSyntaxException;

import java.lang.reflect.Type;
import java.util.Map;

/**
 * Gson 示例:将 JSON 对象字符串反序列化为 Java Map 集合
 */
public class GsonJsonToMapExample {
    public static void main(String[] args) {
        // 1. 创建 Gson 实例
        Gson gson = new Gson();

        // 2. 准备一个 JSON 对象字符串
        String jsonString = "{"
            + "\"name\": \"张三\", "
            + "\"age\": 25, "
            + "\"city\": \"北京\", "
            + "\"isVip\": true, "
            + "\"balance\": 100.50 "
        + "}";

        try {
            // 3. 创建目标泛型类型的 Type 对象 (Map<String, Object>)
            // String 是键的类型,Object 是值的类型 (因为值可以是不同类型)
            Type mapType = new TypeToken<Map<String, Object>>() {}.getType();

            // 4. 调用 fromJson() 方法将 JSON 字符串转换为 Map
            Map<String, Object> userMap = gson.fromJson(jsonString, mapType);

            // 5. 访问 Map 中的数据
            System.out.println("JSON 对象成功反序列化为 Map<String, Object>:");
            System.out.println("- 姓名 (String): " + userMap.get("name"));
            // 注意:Gson 默认会将 JSON 数字解析为 Double 类型
            System.out.println("- 年龄 (Double): " + userMap.get("age"));
            // 需要手动转换为 Integer 或其他数字类型
            int age = ((Double) userMap.get("age")).intValue();
            System.out.println("- 年龄 (int): " + age);
            System.out.println("- 城市 (String): " + userMap.get("city"));
            System.out.println("- 是否 VIP (Boolean): " + userMap.get("isVip"));
            System.out.println("- 余额 (Double): " + userMap.get("balance"));

            // 遍历 Map
            System.out.println("\n遍历 Map:");
            userMap.forEach((key, value) ->
                System.out.println("  - Key: " + key + ", Value: " + value + " (Type: " + value.getClass().getSimpleName() + ")")
            );

        } catch (JsonSyntaxException e) {
            System.err.println("JSON 解析错误: " + e.getMessage());
        } catch (ClassCastException e) {
            System.err.println("类型转换错误: " + e.getMessage());
        }
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57

输出结果:

JSON 对象成功反序列化为 Map<String, Object>:
- 姓名 (String): 张三
- 年龄 (Double): 25.0
- 年龄 (int): 25
- 城市 (String): 北京
- 是否 VIP (Boolean): true
- 余额 (Double): 100.5

遍历 Map:
  - Key: name, Value: 张三 (Type: String)
  - Key: age, Value: 25.0 (Type: Double)
  - Key: city, Value: 北京 (Type: String)
  - Key: isVip, Value: true (Type: Boolean)
  - Key: balance, Value: 100.5 (Type: Double)
1
2
3
4
5
6
7
8
9
10
11
12
13
14

注意: Gson 在将 JSON 数字反序列化到 Map<String, Object> 的 Object 值时,默认会使用 Double 类型。如果需要特定的数字类型(如 Integer, Long, BigDecimal),需要在使用时进行类型转换,或者考虑使用 JsonObject 树模型进行更精确的类型处理。

# 4.3 Java 集合序列化为 JSON 字符串

将 Java List 或 Map 序列化为 JSON 字符串非常直接,使用 gson.toJson() 即可。

import com.google.gson.Gson;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * Gson 示例:将 Java List 和 Map 集合序列化为 JSON 字符串
 */
public class GsonCollectionToJsonExample {
    public static void main(String[] args) {
        // 1. 创建 Gson 实例
        Gson gson = new Gson();

        // --- List 转 JSON 数组字符串 ---
        // 创建一个用户 List
        List<User> userList = new ArrayList<>();
        userList.add(new User("张三", 25));
        userList.add(new User("李四", 30));
        userList.add(new User("王五", 28));

        // 调用 toJson() 将 List 转换为 JSON 数组字符串
        String listJsonString = gson.toJson(userList);
        System.out.println("List<User> 序列化为 JSON 数组字符串:");
        System.out.println(listJsonString);
        // 预期输出: [{"name":"张三","age":25},{"name":"李四","age":30},{"name":"王五","age":28}]

        // --- Map 转 JSON 对象字符串 ---
        // 创建一个 Map 对象
        Map<String, Object> dataMap = new HashMap<>();
        dataMap.put("appName", "My Application");
        dataMap.put("version", "1.2.0");
        dataMap.put("enabled", true);
        dataMap.put("retryCount", 3);
        // 嵌套 Map
        Map<String, String> theme = new HashMap<>();
        theme.put("color", "blue");
        theme.put("font", "Arial");
        dataMap.put("themeConfig", theme);

        // 调用 toJson() 将 Map 转换为 JSON 对象字符串
        String mapJsonString = gson.toJson(dataMap);
        System.out.println("\nMap<String, Object> 序列化为 JSON 对象字符串:");
        System.out.println(mapJsonString);
        // 预期输出: {"appName":"My Application","version":"1.2.0","enabled":true,"retryCount":3,"themeConfig":{"color":"blue","font":"Arial"}}
        // 注意:HashMap 不保证顺序,输出的字段顺序可能不同
    }
    // User 类定义同上
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49

# 五、自定义序列化与反序列化

Gson 提供了强大的自定义能力,允许开发者控制 JSON 转换的细节。

# 5.1 自定义日期格式 (GsonBuilder)

默认情况下,Gson 对 java.util.Date 的序列化格式可能不是我们期望的。可以使用 GsonBuilder 来指定日期格式。

import com.google.gson.Gson;
import com.google.gson.GsonBuilder; // 引入 GsonBuilder
import java.util.Date;

/**
 * Gson 示例:使用 GsonBuilder 自定义日期格式
 */
public class GsonDateFormatExample {
    public static void main(String[] args) {
        // 1. 创建 GsonBuilder 实例
        GsonBuilder gsonBuilder = new GsonBuilder();

        // 2. 使用 setDateFormat() 指定日期格式模式
        // 可以是 SimpleDateFormat 支持的任何有效模式
        String dateFormatPattern = "yyyy-MM-dd HH:mm:ssXXX"; // ISO 8601 格式,带时区
        gsonBuilder.setDateFormat(dateFormatPattern);

        // 3. (可选) 配置其他选项,如格式化输出
        // gsonBuilder.setPrettyPrinting();

        // 4. 调用 create() 方法创建配置好的 Gson 实例
        Gson gson = gsonBuilder.create();

        // 5. 创建包含 Date 字段的对象
        Event event = new Event("系统发布", new Date());

        // 6. 使用配置好的 Gson 实例进行序列化
        String jsonString = gson.toJson(event);
        System.out.println("使用自定义日期格式序列化的 JSON:");
        System.out.println(jsonString);
        // 预期输出类似: {"eventName":"系统发布","eventTime":"2024-08-20 17:30:00+08:00"} (具体时间会变化)

        // 7. 使用配置好的 Gson 实例进行反序列化
        // JSON 字符串中的日期格式必须与 Gson 配置的格式匹配
        String inputJson = "{\"eventName\":\"维护窗口\",\"eventTime\":\"2023-10-01 02:00:00+00:00\"}";
        try {
            Event parsedEvent = gson.fromJson(inputJson, Event.class);
            System.out.println("\n反序列化得到的 Date 对象:");
            // 输出 Date 对象(其 toString() 格式可能与序列化格式不同)
            System.out.println(parsedEvent.getEventTime());
        } catch (Exception e) {
            System.err.println("反序列化日期时出错: " + e.getMessage());
        }
    }
}

/**
 * 包含 Date 字段的事件类
 */
class Event {
    private String eventName;
    private Date eventTime;

    public Event(String eventName, Date eventTime) {
        this.eventName = eventName;
        this.eventTime = eventTime;
    }

    // Getters and Setters...
    public String getEventName() { return eventName; }
    public void setEventName(String eventName) { this.eventName = eventName; }
    public Date getEventTime() { return eventTime; }
    public void setEventTime(Date eventTime) { this.eventTime = eventTime; }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64

# 5.2 忽略特定字段

有多种方法可以在 Gson 序列化/反序列化时忽略 Java 对象的某些字段:

  1. 使用 transient 关键字: 这是 Java 原生的方式,被 transient 修饰的字段默认不会被 Gson 序列化。
  2. 使用 @Expose 注解: 结合 GsonBuilder.excludeFieldsWithoutExposeAnnotation(),可以实现白名单机制,只序列化/反序列化明确标记了 @Expose 的字段。
  3. 使用 ExclusionStrategy: (更高级) 通过 GsonBuilder.setExclusionStrategies() 添加自定义排除策略,可以根据字段名、类型、注解等复杂条件来决定是否排除。

示例:使用 @Expose 注解

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.annotations.Expose; // 引入 Expose 注解

/**
 * Gson 示例:使用 @Expose 注解控制字段的序列化和反序列化
 */
public class GsonExposeExample {
    public static void main(String[] args) {
        // 1. 创建 GsonBuilder 并启用 @Expose 支持
        Gson gson = new GsonBuilder()
                // 调用此方法后,只有显式标记了 @Expose 的字段才会被处理
                .excludeFieldsWithoutExposeAnnotation()
                // (可选) 启用格式化输出
                .setPrettyPrinting()
                .create();

        // 2. 创建带有 @Expose 注解的对象实例
        UserProfile user = new UserProfile("张三", 25, "zhangsan@example.com", "内部备注", "123456");

        // 3. 序列化对象
        // 只有 name, age, email 字段 (标记了 @Expose) 会被包含
        String jsonString = gson.toJson(user);
        System.out.println("--- 使用 @Expose 序列化后的 JSON ---");
        System.out.println(jsonString);
        // 预期输出:
        // {
        //   "name": "张三",
        //   "age": 25,
        //   "email": "zhangsan@example.com"
        // }

        // 4. 准备用于反序列化的 JSON (包含所有字段)
        String inputJson = "{"
            + "\"name\": \"李四\", "
            + "\"age\": 30, "
            + "\"email\": \"lisi@example.com\", "
            + "\"internalNotes\": \"这是李四的备注\", " // 此字段在类中无 @Expose
            + "\"password\": \"secret\""           // 此字段在类中无 @Expose
        + "}";

        // 5. 反序列化 JSON
        UserProfile parsedUser = gson.fromJson(inputJson, UserProfile.class);

        // 输出反序列化后的对象状态
        // 只有 name, age, email 被成功赋值,internalNotes 和 password 保持默认值 (null)
        System.out.println("\n--- 使用 @Expose 反序列化后的 UserProfile 对象 ---");
        System.out.println("Name: " + parsedUser.getName());
        System.out.println("Age: " + parsedUser.getAge());
        System.out.println("Email: " + parsedUser.getEmail());
        System.out.println("Internal Notes: " + parsedUser.getInternalNotes()); // 应为 null
        System.out.println("Password: " + parsedUser.getPassword());           // 应为 null
    }
}

/**
 * 使用 @Expose 注解控制字段可见性的用户资料类
 */
class UserProfile {
    // @Expose 默认同时对序列化和反序列化生效
    @Expose
    private String name;

    @Expose
    private int age;

    @Expose(serialize = true, deserialize = true) // 显式指定序列化和反序列化都包含 (默认行为)
    private String email;

    // 没有 @Expose 注解,当 excludeFieldsWithoutExposeAnnotation() 启用时,此字段会被忽略
    private String internalNotes;

    // 也可以将 @Expose 用在 transient 字段上,如果需要强制包含它
    // @Expose transient String temporaryData;

    // 假设密码也不希望被序列化/反序列化
    private transient String password; // 使用 transient 也可以忽略

    public UserProfile(String name, int age, String email, String internalNotes, String password) {
        this.name = name;
        this.age = age;
        this.email = email;
        this.internalNotes = internalNotes;
        this.password = password;
    }

    // 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 String getInternalNotes() { return internalNotes; }
    public void setInternalNotes(String internalNotes) { this.internalNotes = internalNotes; }
    public String getPassword() { return password; }
    public void setPassword(String password) { this.password = password; }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98

# 5.3 指定 JSON 字段名 (@SerializedName)

如果 Java 字段名与 JSON 字段名不一致(例如 Java 驼峰 vs JSON 下划线),可以使用 @SerializedName 注解。

import com.google.gson.Gson;
import com.google.gson.annotations.SerializedName; // 引入 SerializedName 注解

/**
 * Gson 示例:使用 @SerializedName 指定 JSON 字段名
 */
public class GsonSerializedNameExample {
    public static void main(String[] args) {
        Gson gson = new Gson();

        // --- 序列化 ---
        Product product = new Product("P001", "智能手表", 1999.99, 50);
        String jsonOutput = gson.toJson(product);
        System.out.println("--- 使用 @SerializedName 序列化 ---");
        System.out.println(jsonOutput);
        // 预期输出: {"product_id":"P001","productName":"智能手表","unit_price":1999.99,"stock_count":50}

        // --- 反序列化 ---
        String jsonInput = "{\"product_id\":\"P002\",\"productName\":\"无线充电器\",\"unit_price\":199.0,\"stock_count\":100}";
        Product parsedProduct = gson.fromJson(jsonInput, Product.class);
        System.out.println("\n--- 使用 @SerializedName 反序列化 ---");
        System.out.println("产品 ID: " + parsedProduct.getProductId());
        System.out.println("产品名称: " + parsedProduct.getProductName());
        System.out.println("单价: " + parsedProduct.getUnitPrice());
        System.out.println("库存: " + parsedProduct.getStockCount());
    }
}

/**
 * 使用 @SerializedName 映射 JSON 字段名的产品类
 */
class Product {
    // 将 Java 字段 productId 映射到 JSON 字段 product_id
    @SerializedName("product_id")
    private String productId;

    // 字段名相同,可以不加注解,但加上也无妨
    @SerializedName("productName")
    private String productName;

    // 将 Java 字段 unitPrice 映射到 JSON 字段 unit_price
    @SerializedName("unit_price")
    private double unitPrice;

    // @SerializedName 也可以提供备选名称 (反序列化时用)
    @SerializedName(value = "stock_count", alternate = {"stock", "count"})
    private int stockCount;

    public Product(String productId, String productName, double unitPrice, int stockCount) {
        this.productId = productId;
        this.productName = productName;
        this.unitPrice = unitPrice;
        this.stockCount = stockCount;
    }

    // Getters and Setters...
    public String getProductId() { return productId; }
    public void setProductId(String productId) { this.productId = productId; }
    public String getProductName() { return productName; }
    public void setProductName(String productName) { this.productName = productName; }
    public double getUnitPrice() { return unitPrice; }
    public void setUnitPrice(double unitPrice) { this.unitPrice = unitPrice; }
    public int getStockCount() { return stockCount; }
    public void setStockCount(int stockCount) { this.stockCount = stockCount; }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65

# 六、Gson 高级配置选项 (GsonBuilder)

GsonBuilder 是配置和创建自定义 Gson 实例的工厂类,提供了丰富的选项。

# 6.1 格式化 JSON 输出 (setPrettyPrinting)

使输出的 JSON 字符串带有缩进和换行,提高可读性。

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
// 引入之前的 UserWithAddress 和 Address 类定义

/**
 * Gson 示例:使用 setPrettyPrinting 格式化 JSON 输出
 */
public class GsonPrettyPrintingExample {
    public static void main(String[] args) {
        // 1. 创建 GsonBuilder 并启用格式化输出
        Gson gson = new GsonBuilder()
                .setPrettyPrinting() // 启用"漂亮打印"
                .create();

        // 2. 创建一个嵌套结构的对象
        Address address = new Address("北京", "朝阳区", "100020");
        UserWithAddress user = new UserWithAddress("张三", 25, address);

        // 3. 序列化为格式化的 JSON 字符串
        String prettyJson = gson.toJson(user);
        System.out.println("--- 格式化后的 JSON 输出 ---");
        System.out.println(prettyJson);
        /* 预期输出:
        {
          "name": "张三",
          "age": 25,
          "address": {
            "city": "北京",
            "district": "朝阳区",
            "zipCode": "100020"
          }
        }
        */
    }
}

// 需要包含之前定义的 Address 和 UserWithAddress 类
class Address {
    private String city;     // 城市
    private String district; // 区县
    private String zipCode;  // 邮编
    public Address(String city, String district, String zipCode) { this.city = city; this.district = district; this.zipCode = zipCode; }
    // Getters...
}
class UserWithAddress {
    private String name;    // 用户姓名
    private int age;        // 用户年龄
    private Address address; // 用户地址
    public UserWithAddress(String name, int age, Address address) { this.name = name; this.age = age; this.address = address; }
    // Getters...
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51

# 6.2 处理 null 值 (serializeNulls)

默认情况下,Gson 在序列化时会忽略值为 null 的字段。可以使用 serializeNulls() 让 Gson 输出这些 null 值。

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
// 引入之前的 User 类定义

/**
 * Gson 示例:使用 serializeNulls 控制 null 值的序列化
 */
public class GsonNullValueExample {
    public static void main(String[] args) {
        // --- 默认行为:忽略 null ---
        Gson defaultGson = new Gson();
        User userWithNull = new User("张三", 25);
        userWithNull.setName(null); // 将 name 设置为 null

        String defaultJson = defaultGson.toJson(userWithNull);
        System.out.println("--- 默认序列化 (忽略 null) ---");
        System.out.println(defaultJson); // 预期输出: {"age":25}

        // --- 配置为序列化 null ---
        Gson gsonWithNulls = new GsonBuilder()
                .serializeNulls() // 调用此方法以包含 null 值
                .create();

        String jsonWithNulls = gsonWithNulls.toJson(userWithNull);
        System.out.println("\n--- 使用 serializeNulls() 序列化 ---");
        System.out.println(jsonWithNulls); // 预期输出: {"name":null,"age":25}
    }
    // 需要包含之前定义的 User 类
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29

# 6.3 其他常用 GsonBuilder 配置

  • disableHtmlEscaping(): 默认 Gson 会对 HTML 字符(如 <, >, = 等)进行转义。调用此方法可以禁用 HTML 转义。
  • setFieldNamingPolicy(FieldNamingPolicy policy): 设置字段命名策略,例如 FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES 可以自动将 Java 驼峰命名转换为 JSON 下划线命名。
  • registerTypeAdapter(Type type, Object typeAdapter): 注册自定义的 TypeAdapter 或 JsonSerializer/JsonDeserializer,用于完全控制特定类型的序列化/反序列化逻辑。
  • addSerializationExclusionStrategy(ExclusionStrategy strategy) / addDeserializationExclusionStrategy(ExclusionStrategy strategy): 添加自定义排除策略。

# 七、实战应用场景

# 7.1 在 Spring Boot 中集成 Gson

虽然 Spring Boot 默认使用 Jackson,但可以通过配置轻松替换为 Gson。

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.http.converter.json.GsonHttpMessageConverter; // 引入 Gson 消息转换器
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;

/**
 * Spring Boot 应用示例:配置 Gson 作为默认 JSON 处理器
 */
@SpringBootApplication
public class GsonSpringBootApplication {

    public static void main(String[] args) {
        SpringApplication.run(GsonSpringBootApplication.class, args);
    }

    /**
     * 配置一个自定义的 GsonHttpMessageConverter Bean。
     * Spring Boot 会检测到这个 Bean 并优先使用它来处理 HTTP 请求/响应中的 JSON。
     * 这会覆盖默认的 Jackson 配置。
     *
     * @return 配置好的 GsonHttpMessageConverter
     */
    @Bean
    public GsonHttpMessageConverter gsonHttpMessageConverter() {
        // 1. 创建 GsonBuilder 来定制 Gson 实例
        GsonBuilder gsonBuilder = new GsonBuilder();

        // 2. 配置 Gson (示例配置)
        gsonBuilder.setDateFormat("yyyy-MM-dd HH:mm:ss"); // 设置全局日期格式
        gsonBuilder.setPrettyPrinting();                  // 开发环境下可启用格式化输出
        gsonBuilder.serializeNulls();                     // 序列化 null 值
        // gsonBuilder.excludeFieldsWithoutExposeAnnotation(); // 如果需要 @Expose 支持
        // ... 添加更多自定义配置 ...

        // 3. 创建配置好的 Gson 实例
        Gson gson = gsonBuilder.create();

        // 4. 创建 GsonHttpMessageConverter 并设置自定义的 Gson 实例
        GsonHttpMessageConverter converter = new GsonHttpMessageConverter();
        converter.setGson(gson);

        // 5. 返回配置好的转换器 Bean
        return converter;
    }

    // 可以在 Controller 中直接使用 @RequestBody 和 @ResponseBody,
    // Spring Boot 会自动使用配置的 GsonHttpMessageConverter 进行转换。
    /*
    @RestController
    public class MyController {
        @PostMapping("/users")
        public User createUser(@RequestBody User user) {
            // ... process user ...
            return user; // 返回 User 对象,会被 Gson 序列化为 JSON 响应
        }
    }
    */
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60

在 application.properties 或 application.yml 中,可以通过设置 spring.mvc.converters.preferred-json-mapper=gson 来明确指定优先使用 Gson (如果同时存在 Jackson 和 Gson 依赖)。

# 7.2 处理动态或未知结构的 JSON (树模型)

当 JSON 结构不固定或预先未知时,使用 Gson 的树模型 (JsonElement, JsonObject, JsonArray) 是一个好方法。

import com.google.gson.Gson;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonArray; // 引入 JsonArray
import com.google.gson.JsonParser; // 引入 JsonParser
import com.google.gson.JsonPrimitive; // 引入 JsonPrimitive

/**
 * Gson 示例:使用树模型处理动态结构的 JSON
 */
public class GsonDynamicJsonExample {
    public static void main(String[] args) {
        // 1. 准备一个结构可能变化的 JSON 字符串
        String eventJson = "{"
            + "\"eventType\": \"USER_LOGIN\","
            + "\"timestamp\": 1692520800000,"
            + "\"payload\": {" // payload 结构根据 eventType 可能不同
                + "\"userId\": \"user123\","
                + "\"ipAddress\": \"192.168.1.100\""
            + "}"
        + "}";

        String eventJson2 = "{"
            + "\"eventType\": \"ITEM_PURCHASED\","
            + "\"timestamp\": 1692521000000,"
            + "\"payload\": {"
                + "\"itemId\": \"prod789\","
                + "\"quantity\": 2,"
                + "\"price\": 49.99"
            + "}"
        + "}";

        // 2. 使用 JsonParser 解析 JSON 字符串为 JsonElement
        JsonElement rootElement = JsonParser.parseString(eventJson);
        JsonElement rootElement2 = JsonParser.parseString(eventJson2);

        // 3. 处理第一个事件 (USER_LOGIN)
        processEvent(rootElement);

        // 4. 处理第二个事件 (ITEM_PURCHASED)
        processEvent(rootElement2);
    }

    /**
     * 根据事件类型动态处理 JsonElement
     * @param eventElement 解析后的根 JsonElement
     */
    public static void processEvent(JsonElement eventElement) {
        if (eventElement.isJsonObject()) {
            JsonObject eventObject = eventElement.getAsJsonObject();

            // 获取通用字段
            String eventType = eventObject.get("eventType").getAsString();
            long timestamp = eventObject.get("timestamp").getAsLong();

            System.out.println("\n--- 处理事件 ---");
            System.out.println("事件类型: " + eventType);
            System.out.println("时间戳: " + timestamp);

            // 获取 payload 对象
            JsonObject payload = eventObject.getAsJsonObject("payload");

            // 根据 eventType 动态处理 payload
            switch (eventType) {
                case "USER_LOGIN":
                    String userId = payload.get("userId").getAsString();
                    String ipAddress = payload.get("ipAddress").getAsString();
                    System.out.println("用户登录信息: userId=" + userId + ", ipAddress=" + ipAddress);
                    break;

                case "ITEM_PURCHASED":
                    String itemId = payload.get("itemId").getAsString();
                    int quantity = payload.get("quantity").getAsInt();
                    double price = payload.get("price").getAsDouble();
                    System.out.println("物品购买信息: itemId=" + itemId + ", quantity=" + quantity + ", price=" + price);
                    break;

                default:
                    System.out.println("未知的事件类型,原始 payload: " + payload.toString());
                    break;
            }
        } else {
            System.err.println("输入的不是有效的 JSON 对象事件结构");
        }
    }
    // 需要 User 类定义 (如果选择将 payload 转为 POJO)
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87

输出结果:

--- 处理事件 ---
事件类型: USER_LOGIN
时间戳: 1692520800000
用户登录信息: userId=user123, ipAddress=192.168.1.100

--- 处理事件 ---
事件类型: ITEM_PURCHASED
时间戳: 1692521000000
物品购买信息: itemId=prod789, quantity=2, price=49.99
1
2
3
4
5
6
7
8
9

总结

Gson 作为 Google 推出的一款成熟且广泛使用的 Java JSON 库,以其简洁直观的 API、对复杂对象和泛型的良好支持以及强大的自定义能力赢得了开发者的青睐。

核心优势与功能回顾:

  1. 基础转换: 通过 toJson() 和 fromJson() 轻松实现 Java 对象与 JSON 字符串的双向转换。
  2. 无需注解: 对标准 POJO 无需额外注解即可工作,降低了使用门槛。
  3. 泛型支持: 利用 TypeToken 完美解决了 Java 泛型擦除问题,能够准确地反序列化泛型集合(如 List<T>, Map<K, V>)。
  4. 树模型操作: 提供了 JsonElement, JsonObject, JsonArray 等类,允许像操作 DOM 一样灵活处理动态或未知结构的 JSON 数据。
  5. 强大的自定义能力: GsonBuilder 提供了丰富的配置选项(日期格式、null 值处理、字段命名策略、排除策略、格式化输出等),并支持通过 TypeAdapter 实现终极定制。
  6. 注解支持: 提供了 @SerializedName, @Expose 等注解,用于更细粒度地控制序列化和反序列化行为。
  7. 生态整合: 可以方便地集成到 Spring Boot 等主流框架中。

无论是简单的 DTO 转换、处理复杂的 API 响应,还是操作动态 JSON 数据,Gson 都能提供可靠且高效的解决方案。熟练掌握 Gson 的用法,无疑会大大提升 Java 开发中处理 JSON 数据的效率和代码质量。

编辑此页 (opens new window)
上次更新: 2025/04/06, 10:15:45
FastJson2(JSON处理库)
BeanUtils(对象复制工具)

← FastJson2(JSON处理库) BeanUtils(对象复制工具)→

Theme by Vdoing | Copyright © 2019-2025 程序员scholar
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式