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

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

相关推荐
24k小善几秒前
FlinkUpsertKafka深度解析
java·大数据·flink·云计算
EnigmaCoder20 分钟前
java面向对象编程【高级篇】之多态
java·开发语言
秋名RG25 分钟前
浅谈Java 内存管理:栈与堆,垃圾回收
java·开发语言·jvm
WMSmile1 小时前
Maven下载aspose依赖失败的解决方法
java·maven
Python私教1 小时前
Rust:安全与性能兼得的现代系统编程语言
java·安全·rust
2401_897930061 小时前
Maven 使用教程
java·maven
PXM的算法星球1 小时前
【Java后端】MyBatis 与 MyBatis-Plus 如何防止 SQL 注入?从原理到实战
java·sql·mybatis
zh_xuan1 小时前
java Optional
java·开发语言
阿杜杜不是阿木木1 小时前
03.使用spring-ai玩转MCP
java·人工智能·spring boot·spring·mcp·spring-ai
旧故新长1 小时前
MyBatis 类型处理器(TypeHandler)注册与映射机制:JsonListTypeHandler和JsonListTypeHandler注册时机
java·开发语言·mybatis