序列化 之 fastJson(二)高级功能

Fastjson(尤其是 Fastjson 2.x,包名为 com.alibaba.fastjson2)除了基础的序列化/反序列化外,还提供了大量高级 API,用于处理复杂场景,如:

  • 流式解析(避免内存溢出)
  • 自定义类型转换
  • 字段过滤与动态控制
  • JSONPath 查询
  • 与 Spring MVC 集成
  • 性能调优与缓存机制

本文将系统讲解 Fastjson 的高级用法与 API 示例,以 Fastjson 2.0+ 为主(兼顾 1.x 差异说明)。


一、流式解析(Streaming Parse)—— 处理大 JSON 文件

当 JSON 数据非常大(如 1GB 日志文件),一次性加载到内存会 OOM。Fastjson 提供 JSONReader 流式读取

✅ 示例:逐条读取 JSON 数组中的对象

import com.alibaba.fastjson2.JSONReader;
import java.io.FileReader;
import java.io.IOException;

public class StreamingParseDemo {
    public static void main(String[] args) throws IOException {
        try (FileReader fileReader = new FileReader("users.json");
             JSONReader reader = JSONReader.of(fileReader)) {

            // 假设 users.json 是 [{"name":"A"},{"name":"B"},...]
            reader.startArray(); // 开始数组
            while (reader.hasNext()) {
                User user = reader.read(User.class); // 逐个读取
                System.out.println("User: " + user.name);
            }
            reader.endArray();
        }
    }

    public static class User {
        public String name;
    }
}

💡 优势:内存占用恒定,适合大数据量处理。


二、JSONPath —— 快速提取 JSON 子数据

Fastjson 内置 JSONPath 支持,类似 XPath,用于查询 JSON。

✅ 基础语法示例

String json = """
{
  "company": {
    "name": "Alibaba",
    "employees": [
      {"id": 1, "name": "张三", "dept": "RD"},
      {"id": 2, "name": "李四", "dept": "QA"}
    ]
  }
}
""";

JSONObject obj = JSON.parseObject(json);

// 获取公司名
String companyName = JSONPath.eval(obj, "$.company.name"); // "Alibaba"

// 获取所有员工姓名
List<String> names = JSONPath.eval(obj, "$.company.employees[*].name"); // ["张三", "李四"]

// 条件查询:ID=1 的员工
List<?> emp = JSONPath.eval(obj, "$.company.employees[?(@.id == 1)]");

⚠️ 注意:

  • Fastjson 2.x 中 JSONPath 类位于 com.alibaba.fastjson2.JSONPath
  • 支持复杂表达式:$..name(递归查找所有 name)、$[0:2](切片)等

三、字段过滤(PropertyFilter / NameFilter)

在序列化时动态决定是否输出某个字段,常用于权限控制(如管理员可见密码,普通用户不可见)。

✅ 方式1:使用 NameFilter(重命名或跳过)

User user = new User("admin", "123456");

String json = JSON.toJSONString(user, new NameFilter() {
    @Override
    public String process(Object object, String name, Object value) {
        if ("password".equals(name) && !"admin".equals(getCurrentUser())) {
            return null; // 返回 null 表示跳过该字段
        }
        return name; // 返回原字段名
    }
});

✅ 方式2:使用 PropertyFilter(更直观)

String json = JSON.toJSONString(user, new PropertyFilter() {
    @Override
    public boolean apply(Object source, String name, Object value) {
        // 返回 true 表示保留,false 表示过滤
        if ("password".equals(name)) {
            return "admin".equals(getCurrentUser());
        }
        return true;
    }
});

🔒 应用场景:同一接口对不同角色返回不同字段。


四、自定义类型转换(TypeAdapter / ObjectReader)

当 JSON 字段与 Java 类型不匹配时(如字符串 "true"Boolean),可自定义转换逻辑。

✅ 示例:将任意字符串转 Boolean("1"/"true"/"yes" → true)

public class FlexibleBooleanReader implements ObjectReader<Boolean> {
    @Override
    public Boolean readObject(JSONReader reader, Type fieldType, Object fieldName, long features) {
        String str = reader.readString();
        if (str == null) return null;
        str = str.trim().toLowerCase();
        return "1".equals(str) || "true".equals(str) || "yes".equals(str);
    }
}

// 使用
@JSONField(deserializeUsing = FlexibleBooleanReader.class)
public Boolean enabled;

✅ 全局注册(Fastjson 2.x)

// 创建自定义模块(Fastjson 2.x 推荐方式)
ObjectWriterProvider writerProvider = new ObjectWriterProvider();
ObjectReaderProvider readerProvider = new ObjectReaderProvider();

readerProvider.register(Boolean.class, FlexibleBooleanReader::new);

// 在 toJSONString 或 parseObject 时传入
JSON.toJSONString(obj, 
    JSONWriter.of(writerProvider, ...).getContext());

💡 更推荐在字段上用 @JSONField(deserializeUsing=...) 局部控制。


五、与 Spring MVC 集成(替换 Jackson)

虽然 Spring Boot 默认用 Jackson,但可配置 Fastjson 作为 HTTP 消息转换器。

✅ 步骤(Spring Boot + Fastjson 2.x)

  1. 添加依赖
<dependency>
    <groupId>com.alibaba.fastjson2</groupId>
    <artifactId>fastjson2-extension-spring6</artifactId> <!-- Spring 6 / Boot 3 -->
    <!-- 或 fastjson2-extension-spring5 for Spring Boot 2.x -->
    <version>2.0.57</version>
</dependency>
  1. 配置 WebMvcConfigurer
@Configuration
public class WebConfig implements WebMvcConfigurer {

    @Override
    public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
        FastJsonHttpMessageConverter converter = new FastJsonHttpMessageConverter();

        FastJsonConfig config = new FastJsonConfig();
        config.setWriterFeatures(JSONWriter.Feature.PrettyFormat);
        config.setReaderFeatures(JSONReader.Feature.IgnoreSetNullValue);

        converter.setFastJsonConfig(config);
        converter.setDefaultCharset(StandardCharsets.UTF_8);

        // 支持 application/json
        converter.setSupportedMediaTypes(Arrays.asList(
            MediaType.APPLICATION_JSON,
            MediaType.APPLICATION_JSON_UTF8
        ));

        converters.add(0, converter); // 插入首位,优先使用
    }
}

✅ 控制器中 @ResponseBody / @RequestBody 自动使用 Fastjson。


六、性能优化技巧

1. 启用 ASM 优化(默认已开启)

Fastjson 2.x 默认使用字节码生成加速序列化。

2. 复用 JSONWriter / JSONReader

避免频繁创建解析器对象。

3. 关闭不必要的 Feature

如非必要,不要开启 WriteClassNameWriteMapNullValue 等。

4. 使用 toJSONBytes() 替代 toJSONString().getBytes()

减少字符串中间对象:

byte[] jsonBytes = JSON.toJSONBytes(user); // 直接输出 byte[]

七、高级注解详解

注解 说明
@JSONType(alphabetic = false) 保持字段原始顺序(默认按字母排序)
@JSONType(ignores = {"password"}) 类级别忽略字段
@JSONField(unwrapped = true) 展开嵌套对象字段(类似 Jackson 的 @JsonUnwrapped
@JSONField(label = "sensitive") 配合 LabelFilter 实现标签过滤

unwrapped 示例

public class Address {
    public String city;
    public String street;
}

public class User {
    public String name;
    
    @JSONField(unwrapped = true)
    public Address addr;
}

// 序列化结果: {"name":"张三","city":"杭州","street":"文一西路"}

八、安全加固(必读!)

1. 禁用 AutoType(默认已禁用)

Fastjson 2.x 默认 不支持 @type,无需额外配置。

2. 如必须使用 AutoType,严格白名单

// Fastjson 1.x 方式(不推荐)
ParserConfig.getGlobalInstance().addAccept("com.yourcompany.model.");

// Fastjson 2.x 不建议开启,若需请使用 SafeMode
System.setProperty("fastjson2.parser.safeMode", "true");

3. 升级到最新版

定期关注 Fastjson GitHub 安全公告。


九、Fastjson 1.x 与 2.x 关键差异速查

功能 Fastjson 1.x Fastjson 2.x
包名 com.alibaba.fastjson com.alibaba.fastjson2
流式读取 JSONReader JSONReader(API 更简洁)
JSONPath com.alibaba.fastjson.JSONPath com.alibaba.fastjson2.JSONPath
Spring 集成 FastJsonHttpMessageConverter fastjson2-extension-spring*
AutoType 默认部分开启(危险) 默认完全禁用(安全)
性能 更快(重构 + ASM 优化)

总结:Fastjson 高级能力全景

能力 API / 方法 适用场景
流式解析 JSONReader.of(inputStream) 大文件处理
JSONPath 查询 JSONPath.eval(obj, "$.a.b") 快速提取子数据
动态字段过滤 PropertyFilter / NameFilter 权限控制、脱敏
自定义类型转换 ObjectReader / ObjectWriter 非标准格式兼容
Spring 集成 FastJsonHttpMessageConverter 替换 Jackson
性能优化 toJSONBytes()、ASM、Feature 调优 高并发服务
安全防护 禁用 AutoType、白名单 防 RCE 攻击

📌 建议:新项目优先考虑 Fastjson 2.x;若无特殊需求,也可选用 Jackson(生态更稳、漏洞少)。

posted @ 2026-01-23 17:26  蓝迷梦  阅读(16)  评论(0)    收藏  举报