FastJSON序列化扩展接口与特性详解
结论先行
FastJSON 的 SerializeFilter 接口通过 动态拦截和修改序列化过程,可实现字段名重命名、敏感数据脱敏、字段过滤等高级功能。其核心子接口包括 PropertyPreFilter、ValueFilter、NameFilter 和 ContextValueFilter,分别解决不同场景需求。
接口选择指南
| 过滤器类型 | 适用场景 | 示例 |
|---|---|---|
PropertyPreFilter |
按字段名黑名单/白名单过滤 | 过滤临时字段 _temp |
ValueFilter |
动态修改字段值 | 手机号脱敏 |
NameFilter |
统一字段命名风格 | 驼峰转下划线 |
ContextValueFilter |
根据类或字段类型差异化处理 | 仅对特定类脱敏 |
文章持续更新,可以微信搜一搜「 半个脑袋儿 」第一时间阅读
完整流程图
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
}
}
源码解析
PropertyPreFilter接口定义public interface PropertyPreFilter extends SerializeFilter {
boolean apply(JSONSerializer serializer, Object object, String name);
}
name:当前字段名。- 返回
true表示保留字段,false表示过滤。
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
}
}
源码解析
ValueFilter接口定义public interface ValueFilter extends SerializeFilter {
Object process(Object object, String name, Object value);
}
object:当前序列化的对象实例(可获取其他字段值)。value:当前字段的原始值,需返回修改后的值。
健壮性设计
- 校验
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
}
}
源码解析
- 正则表达式处理
([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
}
}
源码解析
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
}
}
最佳实践
性能优化
- 避免在过滤器中执行耗时操作(如数据库查询)。
- 优先使用
@JSONField处理静态规则,过滤器处理动态逻辑。
全局过滤器注册
// 全局注册 PhoneFilter,对所有序列化生效
SerializeConfig.getGlobalInstance().addFilter(User.class, phoneFilter);
- 谨慎使用全局过滤器,避免影响其他模块。
文章持续更新,可以微信搜一搜「 半个脑袋儿 」第一时间阅读
FastJSON序列化扩展接口与特性详解的更多相关文章
- Git使用总结 Asp.net生命周期与Http协议 托管代码与非托管代码的区别 通过IEnumerable接口遍历数据 依赖注入与控制反转 C#多线程——优先级 AutoFac容器初步 C#特性详解 C#特性详解 WPF 可触摸移动的ScrollViewer控件 .NET(C#)能开发出什么样的APP?盘点那些通过Smobiler开发的移动应用
一,原理 首先,我们要明白Git是什么,它是一个管理工具或软件,用来管理什么的呢?当然是在软件开发过程中管理软件或者文件的不同版本的工具,一些作家也可以用这个管理自己创作的文本文件,由Linus开发的 ...
- Java基础学习总结(33)——Java8 十大新特性详解
Java8 十大新特性详解 本教程将Java8的新特新逐一列出,并将使用简单的代码示例来指导你如何使用默认接口方法,lambda表达式,方法引用以及多重Annotation,之后你将会学到最新的API ...
- C#中的 特性 详解(转载)
本篇幅转载于:http://www.cnblogs.com/rohelm/archive/2012/04/19/2456088.html C#中特性详解 特性提供了功能强大的方法,用于将元数据或声明信 ...
- iOS开发——高级特性&Runtime运行时特性详解
Runtime运行时特性详解 本文详细整理了 Cocoa 的 Runtime 系统的知识,它使得 Objective-C 如虎添翼,具备了灵活的动态特性,使这门古老的语言焕发生机.主要内容如下: 引言 ...
- 《Android群英传》读书笔记 (5) 第十一章 搭建云端服务器 + 第十二章 Android 5.X新特性详解 + 第十三章 Android实例提高
第十一章 搭建云端服务器 该章主要介绍了移动后端服务的概念以及Bmob的使用,比较简单,所以略过不总结. 第十三章 Android实例提高 该章主要介绍了拼图游戏和2048的小项目实例,主要是代码,所 ...
- C#各个版本中的新增特性详解
序言 自从2000年初期发布以来,c#编程语言不断的得到改进,使我们能够更加清晰的编写代码,也更加容易维护我们的代码,增强的功能已经从1.0搞到啦7.0甚至7.1,每一次改过都伴随着.NET Fram ...
- Android群英传笔记——第十二章:Android5.X 新特性详解,Material Design UI的新体验
Android群英传笔记--第十二章:Android5.X 新特性详解,Material Design UI的新体验 第十一章为什么不写,因为我很早之前就已经写过了,有需要的可以去看 Android高 ...
- 单元测试系列之十一:Jmockit之mock特性详解
本文是Jmockit学习过程中,根据官网所列的工具特性进行解读. 1.调用次数约束(Invocation count constraints) 可以通过调用计数约束来指定预期和/或允许匹配给定期望的调 ...
- Java9 新特性 详解
作者:木九天 < Java9 新特性 详解 > Java9 新特性 详解 摘要: 1.目录结构 2.repl工具 jShell命令 3.模块化 4.多版本兼容jar包 5.接口方 ...
- Atitit.jdk java8的语法特性详解 attilax 总结
Atitit.jdk java8的语法特性详解 attilax 总结 1.1. 类型推断这个特别有趣的.鲜为人知的特性1 2. Lambda1 2.1. 内部迭代意味着改由Java类库来进行迭代,而不 ...
随机推荐
- HTML标签-form表单
HTML标签-form表单 在Web开发中,HTML表单(form)是不可或缺的一部分,它承担着用户与Web服务器之间交互的重任.今天,我们就来详细探讨一下HTML中的form表单标签. 一.form ...
- Linux mint安装百度云
deb包下载 BCloud 作者官网https://github.com/XuShaohua/bcloud-packages 链接: https://pan.baidu.com/s/1hskY04G ...
- C#进行word模板占位符替换的几种工具
word模板中,包含一些需要替换的项,比如{{姓名}} {{年龄}}或者$姓名$ $年龄$,从数据库获取信息后,对模板进行替换操作生成新的word文档. 简单对以下四种工具做了一下测试: 1.NPOI ...
- Transformer-Squared:停止微调 LLMs
Transformer-Squared:停止微调 LLMs 自适应大语言模型背后的架构.Transformer-Squared 的数学与代码,以及奇异值分解 DALL-E 生成的图片 我们已经进入了这 ...
- C# Lambda || Linq 效率问题
255条数据 static void Main() { List<IPEndPoint> list = new List<IPEndPoint>(); for (int i = ...
- 【渗透测试】Vulnhub DarkHole
渗透环境 攻击机: IP: 192.168.216.129(Kali) 靶机: IP:192.168.216.130 靶机下载地址:https://www.vulnhub.com/entr ...
- C#(面向对象的托管语言)类库(区别于应用程序)的异常处理思路
1.不要做出任何应用程序才需要考虑抉择策略,不能想当然的决定一些错误情形.具体的一个体现形式是什么异常都捕获.这不是类库的职责,因为无法掌握所有的调用者的使用情形,这些不确定性是委托.虚方法.接口等特 ...
- pnpm:无法加载文件 C:\Users\Five\AppData\Roaming\npm\pnpm.ps1 ,因为在此系统上禁止运行脚本
前言 重装完了电脑系统,运行pnpm 无法加载文件,pnpm -V也不行 解决方案 用管理员方式启动power shell 输入命令:set-ExecutionPolicy RemoteSigned ...
- 从文件到块: 提高 Hugging Face 存储效率
Hugging Face 在 Git LFS 仓库 中存储了超过 30 PB 的模型.数据集和 Spaces.由于 Git 在文件级别进行存储和版本控制,任何文件的修改都需要重新上传整个文件.这在 H ...
- 单线程的Redis速度为什么快?
博客:https://www.emanjusaka.com 博客园:https://www.cnblogs.com/emanjusaka 公众号:emanjusaka的编程栈 by emanjusak ...