Fastjson1 处理额外 / 未知属性

在 Java 开发中,我们经常需要解析 JSON 数据。有时,JSON 中包含的字段比我们定义的 Java 类多,这些多余的字段被称为“额外属性”或“未知属性”。如果处理不当,程序可能会抛出异常或忽略重要数据。本文将为你介绍如何使用 Fastjson1 优雅地处理这些未知属性。

为什么需要处理未知属性?

假设我们有一个简单的 User 类:

public class User {
    private String name;
    private int age;
    // getter/setter 省略
}

现在收到的 JSON 数据如下:

{
    "name": "Alice",
    "age": 25,
    "email": "[email protected]",
    "address": "123 Main St"
}

emailaddressUser 类中没有的属性。默认情况下,Fastjson 会忽略它们,不会报错。但有时我们需要保留这些额外信息,或者至少知道它们的存在。

1 忽略未知属性(默认行为)

Fastjson 默认会忽略未知属性,不会抛出异常。这是最简单的方式:

String json = "{\"name\":\"Alice\",\"age\":25,\"email\":\"[email protected]\"}";
User user = JSON.parseObject(json, User.class);
System.out.println(user.getName()); // 输出: Alice
System.out.println(user.getAge());  // 输出: 25
// email 被自动忽略

2 使用 @JSONField 注解

如果我们想保留某些额外字段,可以在类中使用 @JSONField 注解指定字段名:

public class User {
    private String name;
    private int age;

    @JSONField(name = "email")
    private String email;

    // getter/setter 省略
}

这样,当 JSON 中包含 email 字段时,它会被映射到 email 属性。

3 使用 parseObject 参数

JSON.parseObject 可以接受一个额外的 Feature 参数来控制行为,它使用的是第二个参数:

import com.alibaba.fastjson.parser.Feature;

String json = "{\"name\":\"Alice\",\"age\":25,\"email\":\"[email protected]\"}";

// 默认行为:忽略未知字段
User user = JSON.parseObject(json, User.class, Feature.IgnoreNotMatch);

4 捕获所有未知属性(推荐)

有时我们需要捕获所有额外属性,例如用于日志记录或动态处理。可以使用 @JSONField 配合 Map 类型字段:

public class User {
    private String name;
    private int age;

    @JSONField(deserializeUsing = ExtraProcessor.class)
    private Map<String, Object> extraFields = new HashMap<>();

    // getter/setter
}

但更常用的方法是覆盖 JSONObjectparseObject 行为。Fastjson 提供了 ExtraProcessor 接口:

import com.alibaba.fastjson.parser.deserializer.ExtraProcessor;

User user = JSON.parseObject(json, User.class, new ExtraProcessor() {
    @Override
    public void processExtra(Object object, String key, Object value) {
        System.out.println("发现额外字段: " + key + " = " + value);
        // 可以存储到 Map 或其他地方
    }
});

更优雅的方式是让类实现 ExtraProcessor 接口:

public class User implements ExtraProcessor {
    private String name;
    private int age;
    private Map<String, Object> extraFields = new HashMap<>();

    @Override
    public void processExtra(Object object, String key, Object value) {
        extraFields.put(key, value);
    }

    // getter/setter 省略
}

使用方式:

User user = JSON.parseObject(json, User.class);
System.out.println(user.getExtraFields()); // 输出: {[email protected], address=123 Main St}

实际应用场景

  1. API 网关:接收第三方数据时,某些字段可能是动态的。
  2. 日志记录:记录所有收到的字段以便调试。
  3. 版本兼容:新旧 API 字段不同时保持兼容。

完整示例

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.parser.deserializer.ExtraProcessor;
import java.util.*;

public class ExtraFieldDemo {
    public static void main(String[] args) {
        String json = "{\"name\":\"Bob\",\"age\":30,\"job\":\"engineer\",\"hobby\":\"reading\"}";

        // 使用匿名内部类
        User user = JSON.parseObject(json, User.class, new ExtraProcessor() {
            @Override
            public void processExtra(Object object, String key, Object value) {
                ((User)object).getExtraFields().put(key, value);
            }
        });

        System.out.println("Name: " + user.getName());
        System.out.println("Extra fields: " + user.getExtraFields());
    }
}

class User {
    private String name;
    private int age;
    private Map<String, Object> extraFields = new HashMap<>();

    // getter/setter
    public String getName() { return name; }
    public void setName(String name) { this.name = name; }
    public int getAge() { return age; }
    public void setAge(int age) { this.age = age; }
    public Map<String, Object> getExtraFields() { return extraFields; }
    public void setExtraFields(Map<String, Object> extraFields) { this.extraFields = extraFields; }
}

总结

处理 JSON 中的未知属性是日常开发中的常见需求。Fastjson1 提供了多种方式来处理:默认忽略、注解映射、特性控制以及 ExtraProcessor 接口。对于需要保留额外信息的情况,推荐使用 ExtraProcessor 方案,它既灵活又易于维护。