Fastjson2 自定义序列化器

作为 Java 开发者,我们经常需要处理 JSON 格式的数据。Fastjson2 是一个高性能的 JSON 处理库,虽然内置的序列化机制已经非常强大,但当我们遇到特殊需求时(比如加密字段、格式化日期、过滤敏感信息),就需要自定义序列化器来精确控制数据的输出格式。

本文将带你从零开始了解 Fastjson2 的自定义序列化器,即使你是第一次接触这个主题,也能轻松掌握。

为什么需要自定义序列化器?

假设我们有一个用户对象,包含密码、身份证号等敏感信息。默认序列化会将这些字段原样输出到 JSON 中,这可能带来安全隐患。通过自定义序列化器,我们可以实现:

  • 对密码进行加密或脱敏
  • 只输出非敏感字段
  • 将复杂类型(如枚举、BigInteger)以特定格式输出
  • 实现字段名动态映射

实现 ObjectSerializer 接口

Fastjson2 提供了 ObjectSerializer 接口,我们只需实现它的 write 方法即可。来看一个简单的例子:

 package com.example.domain;

import com.alibaba.fastjson2.annotation.JSONType;
import lombok.Data;

// 定义一个简单的 User 类
@Data
// 这里表示使用自定义序列化注解的方式
@JSONType(serializer = UserSerializer.class)
public class User {
    private String username;
    private String password;
    private String idCard;
}


// 自定义序列化器
package com.example.domain;

import com.alibaba.fastjson2.JSONWriter;
import com.alibaba.fastjson2.writer.ObjectWriter;

import java.lang.reflect.Type;

public class UserSerializer implements ObjectWriter<User> {
    @Override
    public void write(JSONWriter jsonWriter, Object object, Object fieldName, Type fieldType, long features) {
        User user = (User) object;
        jsonWriter.startObject();
        // Fastjson2 必须先写 key,再写 value
        jsonWriter.writeName("username");  // 写 key
        jsonWriter.writeString(user.getUsername());  // 写 value
        // 密码脱敏
        jsonWriter.writeName("password");
        jsonWriter.writeString(maskPassword(user.getPassword()));
        // 身份证脱敏
        jsonWriter.writeName("idCard");
        jsonWriter.writeString(maskIdCard(user.getIdCard()));
        // 结束对象
        jsonWriter.endObject();
    }

    private String maskPassword(String password) {
        if (password == null) return null;
        return password.substring(0, Math.min(2, password.length())) + "****";
    }

    private String maskIdCard(String idCard) {
        if (idCard == null || idCard.length() < 10) return idCard;
        return idCard.substring(0, 6) + "********" + idCard.substring(14);
    }
}

// 测试调用效果
User user = new User();
user.setIdCard("110101199001011234");
user.setPassword("666666");
user.setUsername("张三");
String json = JSON.toJSONString(user);
System.out.println(json);

输出结果为:

{"username""张三","password""66****","idCard""110101********1234"}

注册自定义序列化器

有两种方式注册:

方式一:全局注册

JSON.register(User.class, new UserSerializer());

方式二:使用注解

@JSONType(serializer = UserSerializer.class)
public class User {
    // ...
}

显然我们在开发的时候更多的情况下使用的是方法2上面的例子中也是使用的注解的方式,特别是spring项目中,因为使用声明式和实体类绑定不用手动执行注册代码一看类就知道序列化规则。

数字格式化与日期转换示例

假设我们需要将金额字段自动保留两位小数,并且自定义日期格式:

 package com.example.domain;

import com.alibaba.fastjson2.annotation.JSONType;
import lombok.Data;

import java.math.BigDecimal;
import java.util.Date;

@Data
// 这里表示使用自定义序列化
@JSONType(serializer = OrderSerializer.class)
public class Order {
    private String orderId;
    private BigDecimal amount;
    private Date createTime;
}

// 自定义序列化器
package com.example.domain;

import com.alibaba.fastjson2.JSONWriter;
import com.alibaba.fastjson2.writer.ObjectWriter;

import java.lang.reflect.Type;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.text.SimpleDateFormat;
import java.util.Date;

public class OrderSerializer implements ObjectWriter<Order> {
    @Override
    public void write(JSONWriter jsonWriter, Object object, Object fieldName, Type fieldType, long features) {
        Order order = (Order) object;

        jsonWriter.startObject();

        // 订单号
        jsonWriter.writeName("orderId");
        jsonWriter.writeString(order.getOrderId());

        // 金额保留两位小数
        jsonWriter.writeName("amount");
        BigDecimal amount = order.getAmount();
        jsonWriter.writeName("amount");
        if (amount == null) {
            jsonWriter.writeNull();
        } else {
            // 保留两位小数,四舍五入
            BigDecimal formatted = amount.setScale(2, RoundingMode.HALF_UP);
            jsonWriter.writeDecimal(formatted);
        }

        //  日期格式化
        jsonWriter.writeName("createTime");
        Date createTime = order.getCreateTime();
        if (createTime == null) {
            jsonWriter.writeNull();
        } else {
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            jsonWriter.writeString(sdf.format(createTime));
        }

        jsonWriter.endObject();
    }
}


// 调用方法
Order order = new Order();
order.setAmount(BigDecimal.valueOf(3.1415926));
order.setCreateTime(new Date());
order.setOrderId("123456789");
//注册
String json = JSON.toJSONString(order);
System.out.println(json);
// 输出 {"orderId""123456789","amount","amount"3.14,"createTime""2026-05-07 21:02:32"}

性能优化技巧

自定义序列化器在性能上通常优于反射机制,但需要遵循一些最佳实践:

  1. 复用 JSONWriter:避免频繁创建临时字符串
  2. 避免冗余检查:在 write 方法中直接处理已知类型
  3. 使用基础类型writeInt32writeString 等原生方法比通用 writeObject
// 高效写法示例
jsonWriter.writeInt32("age", user.getAge()); // 直接写入整数
jsonWriter.writeString("name", user.getName()); // 直接写入字符串

总结

自定义序列化器是 Fastjson2 强大的扩展点,它让我们能够精确控制 JSON 输出的过程。通过本文的学习,你应该已经掌握了:

  • 什么时候需要自定义序列化器
  • 如何实现 ObjectWriter 接口
  • 创建和注册自定义序列化器的方法
  • 实际应用中的脱敏、格式化等场景

当遇到默认行为无法满足需求时,不妨尝试自定义序列化器,它会为你打开一扇新的大门。