FastJSON序列化扩展接口与特性详解

结论先行

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:按字段名过滤

场景

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

示例代码
java 复制代码
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 接口定义

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

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

二、ValueFilter:动态修改字段值

场景

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

示例代码(含健壮性校验)
java 复制代码
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 接口定义

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

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

三、NameFilter:字段名重命名

场景

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

示例代码
java 复制代码
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 类不脱敏)。

示例代码
java 复制代码
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 核心方法

    java 复制代码
    public interface BeanContext {
        Class<?> getBeanClass();      // 获取当前对象的类
        Method getMethod();           // 获取当前字段的 getter 方法
        Field getField();             // 获取当前字段的反射对象
    }
    • 可通过 getBeanClass() 判断对象类型,实现差异化处理。

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

场景

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

示例代码
java 复制代码
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. 全局过滤器注册

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

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

相关推荐
bbq粉刷匠23 分钟前
HashMap 底层原理深度拆解(二):putVal 完整链路解析(懒加载 · 链表遍历 · 尾插法)
java·开发语言·哈希算法
Sam_Deep_Thinking31 分钟前
一个靠谱的C端网关服务应该包含什么内容
java·程序员·系统架构
杨运交1 小时前
[055][调度模块]Spring动态任务调度框架的设计与实现
java·后端·spring
白狐_7981 小时前
408 数据结构算法题 01:线性表暴力求解保分指南
java·数据结构·算法
流云鹤1 小时前
03Java学习day(3)
java·学习
tqs_123451 小时前
Agent智能体+Skill插件引擎+Milvus混合检索 技术沉淀
java·python·milvus
严同学正在努力2 小时前
从备份到恢复:我用 30 分钟恢复了误删的核心业务表
android·java·数据库·ai
QQ_21696290963 小时前
Spring Boot 养老院管理系统:从入住、护理到费用结算的全流程实现(源码可领)
java·spring boot·后端
cxoptics3 小时前
冰洲石分束器设计与应用
java
ck-joker4 小时前
M1 Pro跑LLM实测:Ollama+LangChain4j零成本本地大模型开发,比云端API快在哪?
java·语言模型