结论先行

FastJSON 的 SerializeFilter 接口通过 动态拦截和修改序列化过程,可实现字段名重命名、敏感数据脱敏、字段过滤等高级功能。其核心子接口包括 PropertyPreFilterValueFilterNameFilterContextValueFilter,分别解决不同场景需求。

接口选择指南

过滤器类型 适用场景 示例
PropertyPreFilter 按字段名黑名单/白名单过滤 过滤临时字段 _temp
ValueFilter 动态修改字段值 手机号脱敏
NameFilter 统一字段命名风格 驼峰转下划线
ContextValueFilter 根据类或字段类型差异化处理 仅对特定类脱敏

文章持续更新,可以微信搜一搜「 半个脑袋儿 」第一时间阅读

完整流程图

graph TD
A[开始序列化] --> B[遍历对象字段]
B --> C{是否通过 PropertyPreFilter?}
C -->|否| D[丢弃字段]
C -->|是| E[应用 NameFilter 修改字段名]
E --> F[应用 ValueFilter/ContextValueFilter 修改值]
F --> G[生成最终键值对]
G --> H[继续下一个字段]
H --> B
H --> I[生成完整 JSON]

一、PropertyPreFilter:按字段名过滤

场景

过滤对象中不符合命名规范的字段(如临时字段 _tempData)。

示例代码
public class PropertyPreFilterDemo {
public static void main(String[] args) {
User user = new User("admin", "_tempData123", "13800138000"); // 创建过滤器:过滤以 "_" 开头的字段
PropertyPreFilter filter = (serializer, source, name) ->
!name.startsWith("_"); // 返回 true 表示保留该字段 String json = JSON.toJSONString(user, filter);
System.out.println(json);
// 输出:{"name":"admin","phone":"13800138000"}
} static class User {
private String name;
private String _tempData; // 需要过滤的字段
private String phone; public User(String name, String _tempData, String phone) {
this.name = name;
this._tempData = _tempData;
this.phone = phone;
}
// 省略 getter/setter
}
}
源码解析
  1. PropertyPreFilter 接口定义

    public interface PropertyPreFilter extends SerializeFilter {
    boolean apply(JSONSerializer serializer, Object object, String name);
    }
    • name:当前字段名。
    • 返回 true 表示保留字段,false 表示过滤。
  2. Lambda 实现

    (serializer, source, name) -> !name.startsWith("_")
    • 直接通过字段名判断是否保留,简洁高效。

二、ValueFilter:动态修改字段值

场景

对敏感数据(如手机号、身份证号)进行脱敏处理。

示例代码(含健壮性校验)
public class ValueFilterDemo {
public static void main(String[] args) {
User user = new User("李四", "510123199001011234", "13812345678"); // 创建 ValueFilter:脱敏身份证和手机号
ValueFilter filter = new ValueFilter() {
@Override
public Object process(Object object, String name, Object value) {
if (value == null) return null; // 处理空值 switch (name) {
case "idCard":
if (value instanceof String && ((String) value).length() >= 15) {
String idCard = (String) value;
return idCard.substring(0, 6) + "********" + idCard.substring(14);
}
break;
case "phone":
if (value instanceof String && ((String) value).length() == 11) {
String phone = (String) value;
return phone.substring(0, 3) + "****" + phone.substring(7);
}
break;
}
return value;
}
}; String json = JSON.toJSONString(user, filter);
System.out.println(json);
// 输出:{"idCard":"510123********1234","name":"李四","phone":"138****5678"}
} static class User {
private String name;
private String idCard;
private String phone; // 省略构造方法和 getter/setter
}
}
源码解析
  1. ValueFilter 接口定义

    public interface ValueFilter extends SerializeFilter {
    Object process(Object object, String name, Object value);
    }
    • object:当前序列化的对象实例(可获取其他字段值)。
    • value:当前字段的原始值,需返回修改后的值。
  2. 健壮性设计

    • 校验 value 是否为 null,避免空指针异常。
    • 校验数据类型和长度,防止无效脱敏。

三、NameFilter:字段名重命名

场景

统一 JSON 字段命名风格(如 Java 驼峰命名 → JSON 下划线命名)。

示例代码
public class NameFilterDemo {
public static void main(String[] args) {
Product product = new Product(1001, "MacBook Pro", 14999.99); // 创建 NameFilter:驼峰转下划线
NameFilter filter = (object, name, value) -> {
String regex = "([a-z])([A-Z]+)";
String replacement = "$1_$2";
return name.replaceAll(regex, replacement).toLowerCase();
}; String json = JSON.toJSONString(product, filter);
System.out.println(json);
// 输出:{"product_id":1001,"product_name":"MacBook Pro","product_price":14999.99}
} static class Product {
private Integer productId;
private String productName;
private Double productPrice; // 省略构造方法和 getter/setter
}
}
源码解析
  1. 正则表达式处理

    • ([a-z])([A-Z]+):匹配驼峰命名中的大写字母位置。
    • $1_$2:在大写字母前插入下划线。
    • toLowerCase():统一转为小写,符合下划线风格。

四、ContextValueFilter:上下文感知的字段处理

场景

根据不同对象类型动态脱敏(如 User 类手机号脱敏,Order 类不脱敏)。

示例代码
public class ContextValueFilterDemo {
public static void main(String[] args) {
User user = new User("王五", "13800001234");
Order order = new Order(2001, "13800001234"); // 创建 ContextValueFilter:仅对 User 类手机号脱敏
ContextValueFilter filter = new ContextValueFilter() {
@Override
public Object process(
BeanContext context, Object object, String name, Object value) { // 获取字段所属的类
Class<?> clazz = context.getBeanClass(); if (clazz == User.class && "phone".equals(name)) {
return handlePhone((String) value);
}
return value;
} private String handlePhone(String phone) {
if (phone != null && phone.length() == 11) {
return phone.substring(0, 3) + "****" + phone.substring(7);
}
return phone;
}
}; System.out.println("User JSON: " + JSON.toJSONString(user, filter));
// 输出:{"name":"王五","phone":"138****1234"} System.out.println("Order JSON: " + JSON.toJSONString(order, filter));
// 输出:{"orderId":2001,"contactPhone":"13800001234"}
} static class User {
private String name;
private String phone;
// 省略构造方法和 getter/setter
} static class Order {
private Integer orderId;
private String contactPhone;
// 省略构造方法和 getter/setter
}
}
源码解析
  1. BeanContext 核心方法
    public interface BeanContext {
    Class<?> getBeanClass(); // 获取当前对象的类
    Method getMethod(); // 获取当前字段的 getter 方法
    Field getField(); // 获取当前字段的反射对象
    }
    • 可通过 getBeanClass() 判断对象类型,实现差异化处理。

五、组合过滤器与性能优化

场景

同时使用多个过滤器(如脱敏 + 字段名转换)。

示例代码
public class CombinedFilterDemo {
public static void main(String[] args) {
User user = new User("赵六", "13912345678"); // 过滤器1:手机号脱敏
ValueFilter phoneFilter = (obj, name, value) ->
"phone".equals(name) ? "***-****-" + ((String) value).substring(7) : value; // 过滤器2:字段名转下划线
NameFilter nameFilter = (obj, name, value) ->
name.replaceAll("([A-Z])", "_$1").toLowerCase(); // 组合使用两个过滤器
String json = JSON.toJSONString(user, phoneFilter, nameFilter);
System.out.println(json);
// 输出:{"name":"赵六","phone":"***-****-5678"}
} static class User {
private String name;
private String phone;
// 省略构造方法和 getter/setter
}
}
最佳实践
  1. 性能优化

    • 避免在过滤器中执行耗时操作(如数据库查询)。
    • 优先使用 @JSONField 处理静态规则,过滤器处理动态逻辑。
  2. 全局过滤器注册

    // 全局注册 PhoneFilter,对所有序列化生效
    SerializeConfig.getGlobalInstance().addFilter(User.class, phoneFilter);
    • 谨慎使用全局过滤器,避免影响其他模块。

    文章持续更新,可以微信搜一搜「 半个脑袋儿 」第一时间阅读

FastJSON序列化扩展接口与特性详解的更多相关文章

  1. Git使用总结 Asp.net生命周期与Http协议 托管代码与非托管代码的区别 通过IEnumerable接口遍历数据 依赖注入与控制反转 C#多线程——优先级 AutoFac容器初步 C#特性详解 C#特性详解 WPF 可触摸移动的ScrollViewer控件 .NET(C#)能开发出什么样的APP?盘点那些通过Smobiler开发的移动应用

    一,原理 首先,我们要明白Git是什么,它是一个管理工具或软件,用来管理什么的呢?当然是在软件开发过程中管理软件或者文件的不同版本的工具,一些作家也可以用这个管理自己创作的文本文件,由Linus开发的 ...

  2. Java基础学习总结(33)——Java8 十大新特性详解

    Java8 十大新特性详解 本教程将Java8的新特新逐一列出,并将使用简单的代码示例来指导你如何使用默认接口方法,lambda表达式,方法引用以及多重Annotation,之后你将会学到最新的API ...

  3. C#中的 特性 详解(转载)

    本篇幅转载于:http://www.cnblogs.com/rohelm/archive/2012/04/19/2456088.html C#中特性详解 特性提供了功能强大的方法,用于将元数据或声明信 ...

  4. iOS开发——高级特性&Runtime运行时特性详解

    Runtime运行时特性详解 本文详细整理了 Cocoa 的 Runtime 系统的知识,它使得 Objective-C 如虎添翼,具备了灵活的动态特性,使这门古老的语言焕发生机.主要内容如下: 引言 ...

  5. 《Android群英传》读书笔记 (5) 第十一章 搭建云端服务器 + 第十二章 Android 5.X新特性详解 + 第十三章 Android实例提高

    第十一章 搭建云端服务器 该章主要介绍了移动后端服务的概念以及Bmob的使用,比较简单,所以略过不总结. 第十三章 Android实例提高 该章主要介绍了拼图游戏和2048的小项目实例,主要是代码,所 ...

  6. C#各个版本中的新增特性详解

    序言 自从2000年初期发布以来,c#编程语言不断的得到改进,使我们能够更加清晰的编写代码,也更加容易维护我们的代码,增强的功能已经从1.0搞到啦7.0甚至7.1,每一次改过都伴随着.NET Fram ...

  7. Android群英传笔记——第十二章:Android5.X 新特性详解,Material Design UI的新体验

    Android群英传笔记--第十二章:Android5.X 新特性详解,Material Design UI的新体验 第十一章为什么不写,因为我很早之前就已经写过了,有需要的可以去看 Android高 ...

  8. 单元测试系列之十一:Jmockit之mock特性详解

    本文是Jmockit学习过程中,根据官网所列的工具特性进行解读. 1.调用次数约束(Invocation count constraints) 可以通过调用计数约束来指定预期和/或允许匹配给定期望的调 ...

  9. Java9 新特性 详解

    作者:木九天   <   Java9 新特性 详解  > Java9 新特性 详解 摘要: 1.目录结构 2.repl工具 jShell命令 3.模块化 4.多版本兼容jar包 5.接口方 ...

  10. Atitit.jdk java8的语法特性详解 attilax 总结

    Atitit.jdk java8的语法特性详解 attilax 总结 1.1. 类型推断这个特别有趣的.鲜为人知的特性1 2. Lambda1 2.1. 内部迭代意味着改由Java类库来进行迭代,而不 ...

随机推荐

  1. HTML标签-form表单

    HTML标签-form表单 在Web开发中,HTML表单(form)是不可或缺的一部分,它承担着用户与Web服务器之间交互的重任.今天,我们就来详细探讨一下HTML中的form表单标签. 一.form ...

  2. Linux mint安装百度云

    deb包下载 BCloud 作者官网https://github.com/XuShaohua/bcloud-packages 链接: https://pan.baidu.com/s/1hskY04G ...

  3. C#进行word模板占位符替换的几种工具

    word模板中,包含一些需要替换的项,比如{{姓名}} {{年龄}}或者$姓名$ $年龄$,从数据库获取信息后,对模板进行替换操作生成新的word文档. 简单对以下四种工具做了一下测试: 1.NPOI ...

  4. Transformer-Squared:停止微调 LLMs

    Transformer-Squared:停止微调 LLMs 自适应大语言模型背后的架构.Transformer-Squared 的数学与代码,以及奇异值分解 DALL-E 生成的图片 我们已经进入了这 ...

  5. C# Lambda || Linq 效率问题

    255条数据 static void Main() { List<IPEndPoint> list = new List<IPEndPoint>(); for (int i = ...

  6. 【渗透测试】Vulnhub DarkHole

    渗透环境 攻击机:   IP: 192.168.216.129(Kali) 靶机:     IP:192.168.216.130 靶机下载地址:https://www.vulnhub.com/entr ...

  7. C#(面向对象的托管语言)类库(区别于应用程序)的异常处理思路

    1.不要做出任何应用程序才需要考虑抉择策略,不能想当然的决定一些错误情形.具体的一个体现形式是什么异常都捕获.这不是类库的职责,因为无法掌握所有的调用者的使用情形,这些不确定性是委托.虚方法.接口等特 ...

  8. pnpm:无法加载文件 C:\Users\Five\AppData\Roaming\npm\pnpm.ps1 ,因为在此系统上禁止运行脚本

    前言 重装完了电脑系统,运行pnpm 无法加载文件,pnpm -V也不行 解决方案 用管理员方式启动power shell 输入命令:set-ExecutionPolicy RemoteSigned ...

  9. 从文件到块: 提高 Hugging Face 存储效率

    Hugging Face 在 Git LFS 仓库 中存储了超过 30 PB 的模型.数据集和 Spaces.由于 Git 在文件级别进行存储和版本控制,任何文件的修改都需要重新上传整个文件.这在 H ...

  10. 单线程的Redis速度为什么快?

    博客:https://www.emanjusaka.com 博客园:https://www.cnblogs.com/emanjusaka 公众号:emanjusaka的编程栈 by emanjusak ...