Fastjson2 反序列化 parseObject
在Java开发中反序列化即json字符串转对象或者集合是常见的需求,在Fastjson2 中反序列化方法是 JSON.parseObject(String text, Class,接下来通过例子说明JSON 字符串转换为 Java 对象
什么是反序列化?
在开始之前,先简单解释一下概念。序列化是将 Java 对象转换成 JSON 字符串的过程,而反序列化则是反过来,将 JSON 字符串转换回 Java 对象。parseObject 就是 Fastjson2 中用于反序列化的核心方法之一。
处理单个对象
假设我们有一个简单的 Java 类:
public class User {
private String name;
private int age;
private String email;
// 提供 getter/setter 方法,或者使用lombok注解
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; }
}
现在,我们有一段 JSON 字符串,想要转换成 User 对象:
import com.alibaba.fastjson2.JSON;
String jsonString = "{\"name\":\"张三\",\"age\":25,\"email\":\"[email protected]\"}";
// 使用 parseObject 反序列化
User user = JSON.parseObject(jsonString, User.class);
System.out.println("姓名:" + user.getName());
System.out.println("年龄:" + user.getAge());
System.out.println("邮箱:" + user.getEmail());
输出结果:
姓名:张三
年龄:25
邮箱:[email protected]
以上是最简单的单个对象反序列化的例子,通过 JSON.parseObject(String text, Class<T> clazz) 方法完成了json字符串转Java对象的需求。
处理复杂嵌套对象
实际开发中,JSON 数据往往更复杂。比如用户地址包含城市街道这种结构:
public class Address {
private String city;
private String street;
// getter/setter 略
}
public class User {
private String name;
private Address address;
// getter/setter 略
}
对应的 JSON:
{
"name": "李四",
"address": {
"city": "北京",
"street": "长安街"
}
}
反序列化代码完全相同:
String json = "{\"name\":\"李四\",\"address\":{\"city\":\"北京\",\"street\":\"长安街\"}}";
User user = JSON.parseObject(json, User.class);
System.out.println(user.getAddress().getCity()); // 输出:北京
Fastjson2 会自动递归处理嵌套对象,不需要额外配置。
解析 JSON 数组
如果 JSON 是一个数组,可以使用 parseArray:
String jsonArray = "[{\"name\":\"用户1\"},{\"name\":\"用户2\"}]";
List<User> users = JSON.parseArray(jsonArray, User.class);
for (User user : users) {
System.out.println(user.getName());
}
输出结果
用户1
用户2
泛型处理TypeReference
TypeReference是反序列化使用最多的地方,而这恰恰是日常开发中最容易出错的地方。
若不使用 TypeReference,直接解析泛型类型(如 Result<Data>),最终得到的 data 字段很可能会变成一个内部的 JSONObject(即“泛型擦除”问题),从而导致类型转换异常。
TypeReference 是专门为“绕过泛型擦除”而设计的工具。它通过创建一个匿名内部类,让 fastjson2 在运行时能“回忆”起完整的泛型类型。
泛型反序列化示例
以下列举了几种最常见的泛型反序列化场景,供你参考:
1. 解析泛型集合 (List<T>)
最常见的场景,用于指定 List 里存放的具体对象。
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.TypeReference;
import java.util.List;
String json = "[{\"id\":1,\"name\":\"Apple\"}, {\"id\":2,\"name\":\"Banana\"}]";
// 错误写法:parseObject(json, List.class) -> 拿到的 List 里是 JSONObject
// 正确写法:使用 TypeReference
List<Product> productList = JSON.parseObject(json, new TypeReference<List<Product>>() {});
2. 解析泛型类(嵌套泛型结构)
这种写法常用于解析标准化的 API 响应体(如 Result<T>)。
// 定义通用响应类
public class Result<T> {
private int code;
private T data;
// 省略 getter/setter
}
// 解析 JSON
String json = "{\"code\":200,\"data\":{\"id\":1,\"name\":\"Apple\"}}";
// 指定内部 data 的具体类型
Result<Product> result = JSON.parseObject(json, new TypeReference<Result<Product>>() {});
Product p = result.getData(); // p 是 Product 类型,无需强制转换
3. 解析复杂嵌套 (Map<K, V>)
当 Map 的 Value 是复杂类型时,利用 TypeReference 指明结构。
String json = "{\"group1\":[{\"id\":1}], \"group2\":[{\"id\":2}]}";
// 解析为 Map<String, List<Product>>
Map<String, List<Product>> map = JSON.parseObject(json, new TypeReference<Map<String, List<Product>>>() {});
避坑要点
在使用 TypeReference 处理泛型时,有几个细节值得特别注意:
- 别忘了最后的
{}:new TypeReference<List<String>>() {}结尾的大括号绝对不能省。这是创建匿名内部类的关键语法,没有它,泛型信息就可能丢失。 - 类属性必须是
public或提供Setter: 如果反序列化后对象的字段值为null,通常是因为该字段不是public且没有对应的public的setter方法。fastjson2默认只处理公开的字段和方法。 Stack集合的特殊处理: 如果你的数据结构里用到了Stack,fastjson2可能会解析失败。官方更推荐用Deque接口或其实现类(如ArrayDeque)来代替Stack。
常见问题与注意事项
1. 字段名不匹配
如果 JSON 中的字段名和 Java 属性名不一致,可以使用 @JSONField 注解:
public class User {
@JSONField(name = "user_name")
private String name;
}
看下面的例子,你也可以看Fastjons2 JsonField注解文章的完整文档。
package com.example.domain;
import com.alibaba.fastjson2.annotation.JSONField;
import lombok.Data;
import java.util.Date;
@Data
public class User {
private Integer id;
@JSONField(name = "user_name")
private String name;
private Integer age;
private Date birthday;
private String email;
private Address address;
}
package com.example.utils;
import com.alibaba.fastjson2.JSON;
import com.example.domain.User;
public class Fastjson2Test {
public static void main(String[] args) {
// JSON 中的 name 字段名为 user_name
String json = "{\n" +
" \"id\": 1001,\n" +
" \"user_name\": \"张三\",\n" + // 注意这里是 user_name
" \"age\": 25,\n" +
" \"email\": \"[email protected]\"\n" +
"}";
// 反序列化:JSON 转 Java 对象
User user = JSON.parseObject(json, User.class);
System.out.println("ID: " + user.getId()); // 1001
System.out.println("Name: " + user.getName()); // 张三(正常映射)
System.out.println("Age: " + user.getAge()); // 25
System.out.println("Email: " + user.getEmail()); // [email protected]
}
}
上面例子中JSON 中的 user_name 会自动映射到 Java 对象的 name 属性
其他字段(id、age、email 等)保持默认映射规则(JSON字段名与Java属性名一致)
2. 类型安全
反序列化时指定的 class 类型必须准确,否则会抛出异常。
String json = "{\"id\":1001,\"name\":\"李四\",\"age\":\"不是数字\"}";
try {
User user = JSON.parseObject(json, User.class);
System.out.println("Age: " + user.getAge());
} catch (JSONException e) {
System.out.println("反序列化失败!类型不匹配");
System.out.println("错误信息:" + e.getMessage());
// 输出 错误信息:parseInt error, value : 不是数字
}
3. 空值处理
这是序列化的例子,Fastjson2 默认会忽略 null 值(不输出为 null 的字段)。如果需要保留 null 值,可以配置序列化特性JSONWriter.Feature.WriteNulls。
User user = new User();
user.setId(1001);
user.setName("张三");
// age = null, email = null
// 默认行为:忽略 null
String json1 = JSON.toJSONString(user);
System.out.println("默认(忽略null): " + json1);
// 输出: {"id":1001,"name":"张三"}
// 配置 WriteNulls:保留 null
String json2 = JSON.toJSONString(user, JSONWriter.Feature.WriteNulls);
System.out.println("配置WriteNulls(保留null): " + json2);
// 输出: {"address":null,"age":null,"birthday":null,"email":null,"id":1001,"name":"张三"}
性能小贴士
对于高频反序列化场景,可以缓存 Class 引用,避免重复的类加载开销。Fastjson2 本身已经做了大量优化,但合理使用仍然能提升性能。
结语
parseObject 是 Fastjson2 最基础也最强大的功能。掌握了它,你就能轻松处理 90% 的 JSON 反序列化需求。
如果 JSON 中有多余的字段(Java 类中没有对应的属性),解析不会失败,Fastjson2 在反序列化时默认会忽略 JSON 中多余的字段,不会抛出异常。

