Fastjson2 快速上手使用指南

作为 Java 开发者,JSON 处理几乎是日常工作中最基础也是最频繁的操作之一。现在介绍 Fastjson2库的使用,它是阿里开源的下一代高性能 JSON 库,它相比老版 Fastjson 在性能和安全性上都有了显著提升。

为什么选择 Fastjson2?

  • 性能卓越:在序列化和反序列化速度上,Fastjson2 相比其他 JSON 库(如 Jackson、Gson)有 2-3 倍的提升
  • 安全性增强:修复了 Fastjson1 中的 AutoType 相关漏洞,默认关闭了自动类型绑定
  • API 友好:支持链式调用、Lambda 表达式、Kotlin 等现代语法
  • 功能丰富:支持 JSONPath、JSON Schema、国际化等高级特性
  • 零依赖:核心包无任何第三方依赖,体积小(约 <1MB)

安全性机制详解

Fastjson2 从架构层面彻底移除了 Fastjson 1.x 中导致 AutoType 漏洞的机制,从根本上解决了远程代码执行等安全风险。Fastjson2 默认关闭了自动类型绑定,并引入了白名单机制、类加载隔离和反序列化沙箱等安全策略,使得企业可以放心使用。在实际使用中,建议始终保持默认的 SafeMode 安全模式,除非明确需要 AutoType 功能且经过充分的安全评估。

环境准备Maven

在 Maven 项目的 pom.xml 中添加依赖:

<dependency>
    <groupId>com.alibaba.fastjson2</groupId>
    <artifactId>fastjson2</artifactId>
    <version>2.0.61</version>
</dependency>

如果使用 Gradle:

dependencies {
    implementation 'com.alibaba.fastjson2:fastjson2:2.0.61'
}

Fastjson v1 兼容模块

如果原来使用 Fastjson 1.2.x 版本,可以引入兼容包以降低升级成本。注意:兼容包不能保证 100% 兼容,请务必充分测试验证。

Maven 依赖

<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>fastjson</artifactId>
    <version>2.0.61</version>
</dependency> 

Gradle 依赖

dependencies {
    implementation 'com.alibaba:fastjson:2.0.61'
} 

Fastjson Kotlin 集成模块

如果项目使用 Kotlin 开发,推荐引入 fastjson2-kotlin 模块,该模块针对 Kotlin 特性进行了优化(如支持数据类、空安全等)。

Maven 依赖

<dependency>
    <groupId>com.alibaba.fastjson2</groupId>
    <artifactId>fastjson2-kotlin</artifactId>
    <version>2.0.61</version>
</dependency> 

Gradle 依赖

dependencies {
    implementation("com.alibaba.fastjson2:fastjson2-kotlin:2.0.61")
} 

Fastjson Extension 扩展模块

如果项目集成了 Spring Framework、Spring Boot 等框架,可以引入 fastjson2-extension 模块,提供与框架的无缝集成支持。

Maven 依赖

<dependency>
    <groupId>com.alibaba.fastjson2</groupId>
    <artifactId>fastjson2-extension</artifactId>
    <version>2.0.61</version>
</dependency> 

Gradle 依赖

dependencies {
    implementation 'com.alibaba.fastjson2:fastjson2-extension:2.0.61'
} 

基础用法:序列化与反序列化

Fastjson2 的核心操作只有两个:将 Java 对象转为 JSON 字符串(序列化),以及将 JSON 字符串转回 Java 对象(反序列化)。

1. 序列化(对象 → JSON)

import com.alibaba.fastjson2.JSON;
import java.time.LocalDate;

// 定义一个简单的实体类
public class User {
    private String name;
    private int age;
    private LocalDate birthday;

    // 构造器、getter/setter 省略(可使用 Lombok @Data)
}

// 序列化
User user = new User();
user.setName("张三");
user.setAge(30);
user.setBirthday(LocalDate.of(1996, 5, 15));

String jsonString = JSON.toJSONString(user);
System.out.println(jsonString);
// 输出:{"age":30,"birthday":"1996-05-15","name":"张三"}

2. 反序列化(JSON → 对象)

String json = "{\"name\":\"李四\",\"age\":32,\"birthday\":\"1994-08-20\"}";

User user = JSON.parseObject(json, User.class);
System.out.println(user.getName());  // 输出:李四
System.out.println(user.getAge());   // 输出:32

3. 处理集合与泛型

泛型请参考这里

// 解析 JSON 数组
String arrayJson = "[{\"name\":\"王五\",\"age\":25},{\"name\":\"赵六\",\"age\":32}]";
List<User> userList = JSON.parseArray(arrayJson, User.class);
System.out.println(userList.size());  // 输出:2

// 使用 TypeReference 处理复杂泛型
String mapJson = "{\"key1\":[1,2,3],\"key2\":[4,5,6]}";
Map<String, List<Integer>> map = JSON.parseObject(
    mapJson, 
    new TypeReference<Map<String, List<Integer>>>(){}
);
System.out.println(map.get("key1"));  // 输出:[1, 2, 3]

处理泛型中的泛型例子:

// 定义一个泛型响应类
public class Result<T> {
    public int code;
    public T data;
}

// 反序列化时指定 T 的具体类型
String json = "{\"code\":200,\"data\":{\"name\":\"王五\",\"age\":30}}";
Result<User> result = JSON.parseObject(json, new TypeReference<Result<User>>(){});

4. JSONObject / JSONArray 解析

在许多场景下,我们并不需要定义完整的 Java 实体类,而只需要临时解析 JSON 数据。Fastjson2 提供了 JSONObjectJSONArray 来完成这类手动解析任务。

// 定义User类
@Data
public class User {
    private int age;
    private String name;

    public User(int age, String name) {
        this.age = age;
        this.name = name;
    }

}
// 解析 JSON 字符串为 JSONObject
String text = "{\"id\": 2, \"name\": \"fastjson2\"}";
JSONObject obj = JSON.parseObject(text);
int id = obj.getIntValue("id");      // 2
String name = obj.getString("name"); // "fastjson2"

// 解析 JSON 字符串为 JSONArray
String arrayText = "[2, \"fastjson2\"]";
JSONArray array = JSON.parseArray(arrayText);
int id2 = array.getIntValue(0);       // 2
String name2 = array.getString(1);    // "fastjson2"

// 从 JSONObject / JSONArray 中提取 Java 对象
User userFromObj = obj.getObject("key", User.class);
int idValue = array.getIntValue(0);
String nameValue = array.getString(1);
User userFromArray = new User(idValue, nameValue);

// JSONObject / JSONArray 转为 Java 对象
User user = obj.toJavaObject(User.class);
List<User> users = new ArrayList<>();
int idValue1 = array.getIntValue(0);
String nameValue1 = array.getString(1);
users.add(new User(idValue1, nameValue1));

JSONPath 支持

Fastjson2 将 JSONPath 内建为原生操作,无需独立解析器或额外转换,可直接在 JSON 对象上执行路径查询与数据提取。JSONPath 是一种用于在 JSON 文档中定位和提取数据的查询语言,类似于 XPath 在 XML 中的作用。通过 JSONPath,可以直接从 JSON 中提取部分数据,无需完整解析整个文档。

String text = "{\"id\": 100, \"name\": \"Alice\", \"scores\": [85, 92, 78]}";

// 创建 JSONPath(可缓存复用,以提升性能)
JSONPath path = JSONPath.of("$.id");

// 从 JSON 字符串中提取数据
JSONReader parser = JSONReader.of(text);
Object result = path.extract(parser);  // 结果为 100

// 对于二进制 JSONB 格式的数据,同样支持 JSONPath 查询
byte[] bytes = ...;
JSONPath path2 = JSONPath.of("$.id");
JSONReader reader = JSONReader.ofJSONB(bytes);
Object result2 = path2.extract(reader); 

JSONB 二进制格式

Fastjson2 除了支持标准的文本 JSON 格式外,还提供了 JSONB(Fastjson2 Binary)二进制序列化格式。JSONB 相比文本 JSON 在序列化体积和解析速度上都有显著优势,特别适合在高性能场景下使用。

JSONB的详细说明,请看这里

// 将 Java 对象序列化为 JSONB 字节数组
User user = new User();
user.setName("张三");
user.setAge(28);

byte[] bytes = JSONB.toBytes(user);
// 也可以使用特性进行优化
byte[] bytesOptimized = JSONB.toBytes(user, JSONWriter.Feature.BeanToArray);

// 将 JSONB 数据反序列化为 Java 对象
byte[] bytesFrom = ...;  // JSONB 格式的字节数组
User user2 = JSONB.parseObject(bytesFrom, User.class);

// 支持数组映射特性
User userOptimized = JSONB.parseObject(bytesFrom, User.class, JSONReader.Feature.SupportArrayToBean);

常用配置与特性

字段命名策略

// 使用下划线分隔命名(例如 user_name → userName)
String json = JSON.toJSONString(user, JSONWriter.Feature.FieldBased);

日期格式化

// 全局日期格式化
JSON.config("yyyy-MM-dd'T'HH:mm:ssXXX", TimeZone.getTimeZone("Asia/Shanghai"));

// 或者使用注解自定义格式
public class User {
    @JSONField(format = "yyyy/MM/dd")
    private LocalDate birthday;
}

忽略空值

String json = JSON.toJSONString(user, JSONWriter.Feature.WriteMapNullValue);

@JSONField 注解详解

@JSONField 注解是 Fastjson2 中最常用的配置注解,支持以下常用属性:

属性作用示例
name指定 JSON 字段与 Java 字段的映射名称@JSONField(name = "user_name")
format指定日期格式@JSONField(format = "yyyy-MM-dd HH:mm:ss")
serialize是否序列化该字段@JSONField(serialize = false)
deserialize是否反序列化该字段@JSONField(deserialize = false)
alternateNames指定备用名称,支持多个别名@JSONField(alternateNames = {"uid", "userId"})
public class User {
    @JSONField(name = "user_name")
    private String name;

    @JSONField(format = "yyyy-MM-dd")
    private LocalDate birthday;

    @JSONField(serialize = false)
    private String password;
} 

实际案例:Web API 交互

以下是一个完整的实际应用场景,模拟从 REST API 获取用户数据并解析:

// 模拟 API 返回的 JSON
String apiResponse = """
    {
        "code": 200,
        "message": "success",
        "data": [
            {"id": 1, "name": "Alice", "scores": [85, 92, 78]},
            {"id": 2, "name": "Bob", "scores": [90, 88, 95]}
        ]
    }
    """;

// 定义嵌套结构
record ApiResult<T>(int code, String message, T data) {}
record Student(int id, String name, List<Integer> scores) {}

// 解析
ApiResult<List<Student>> result = JSON.parseObject(
    apiResponse, 
    new TypeReference<ApiResult<List<Student>>>(){}
);

// 使用数据
result.data().forEach(student -> {
    double avg = student.scores().stream()
        .mapToInt(Integer::intValue)
        .average()
        .orElse(0.0);
    System.out.printf("%s 的平均分是 %.1f%n", student.name(), avg);
});
// 输出:
// Alice 的平均分是 85.0
// Bob 的平均分是 91.0

性能对比速览(非严谨测试)

操作Fastjson2JacksonGson
序列化 10万次120ms310ms450ms
反序列化 10万次150ms380ms520ms

性能优化最佳实践

  1. 处理超大对象:当序列化的 JSON 超过 10MB 时,建议启用 LargeObject 特性,该特性采用流式处理替代全缓冲模式,可显著降低内存使用量:
    String result = JSON.toJSONString(dataClass, JSONWriter.Feature.LargeObject);
  2. API 设计建议:建议不要在代码中直接使用 Fastjson2 的 API,而是封装一个统一的 JSON 工具类。这样可以降低对特定 JSON 库的依赖,方便未来库的升级或替换。
  3. 泛型处理注意事项:处理泛型时必须使用 TypeReference,否则会导致类型信息丢失:
    正确:Map<String, List<Integer>> map = JSON.parseObject(json, new TypeReference<Map<String, List<Integer>>>() {});
    错误:Map<String, List<Integer>> map = JSON.parseObject(json, Map.class);

从 Fastjson 1.x 迁移指南

从 Fastjson 1.x 升级到 Fastjson 2.x 时,需要注意以下要点:

  • 包名变更:从 com.alibaba.fastjson 变更为 com.alibaba.fastjson2,直接替换包名即可。
  • 注解行为变更:Fastjson 2.x 更加遵循 JSON 规范,@JSONField 的 name 属性现在要求字段名称完全匹配(除非显式配置别名)。
  • 引入兼容模块:如果原来使用 Fastjson 1.2.x 版本,可以使用兼容包 com.alibaba:fastjson:2.0.61,但不能保证 100% 兼容,请仔细测试验证。

更多迁移细节请参考

总结与最佳实践

  1. 优先使用 Fastjson2:新项目推荐直接使用 Fastjson2,老项目可以逐步迁移
  2. 避免使用 AutoType:除非必要,否则保持默认的 SafeMode(安全模式)
  3. 善用 TypeReference:处理泛型时一定要使用 TypeReference
  4. 注意性能敏感场景:配合 @JSONField 注解和 JSONWriter.Feature 可以进一步优化

Fastjson2 的学习曲线非常平缓,从今天开始,不妨在你的项目中将老版 Fastjson 或 Jackson 替换为 Fastjson2,体验一下“快”的快乐!