Fastjson2 反序列化 parseObject

在Java开发中反序列化即json字符串转对象或者集合是常见的需求,在Fastjson2 中反序列化方法是 JSON.parseObject(String text, Class clazz),接下来通过例子说明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>)

MapValue 是复杂类型时,利用 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 处理泛型时,有几个细节值得特别注意:

  1. 别忘了最后的 {} new TypeReference<List<String>>() {} 结尾的大括号绝对不能省。这是创建匿名内部类的关键语法,没有它,泛型信息就可能丢失。
  2. 类属性必须是 public 或提供 Setter 如果反序列化后对象的字段值为 null,通常是因为该字段不是 public 且没有对应的 publicsetter 方法。fastjson2 默认只处理公开的字段和方法。
  3. Stack 集合的特殊处理: 如果你的数据结构里用到了 Stackfastjson2 可能会解析失败。官方更推荐用 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 中多余的字段,不会抛出异常。