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);
    • 谨慎使用全局过滤器,避免影响其他模块。

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

相关推荐
是小李呀~9 分钟前
【工作梳理】怎么把f12里面的东西导入到postman
java
攀小黑10 分钟前
Java 多线程加锁 synchronized 关键字 字符串当做key
java·开发语言
余华余华23 分钟前
2024年蓝桥杯Java B组省赛真题超详解析-分布式队列
java·职场和发展·蓝桥杯
破罐子不摔26 分钟前
【C#使用S7.NET库读取和写入西门子PLC变量】
java·c#·.net
可爱的霸王龙37 分钟前
JVM——模型分析、回收机制
java·jvm
神秘的t38 分钟前
javaSE————网络原理
java·网络
hongweihao40 分钟前
啥?有分布式锁都还能被突破
java·后端
BeerBear41 分钟前
记一次Kill <Pid> Java进程无法退出的问题处理
java·后端·spring
Seven971 小时前
【Guava】IO工具
java
独行soc1 小时前
2025年渗透测试面试题总结-某腾某讯-技术安全实习生升级(题目+回答)
java·python·安全·web安全·面试·职场和发展·红蓝攻防