反序列化时如何将对象展开为列表

作者:技术拾光时间:2026-07-02 08:07:06浏览:231

利用 @JsonValue 注解,Jackson 可以把一个对象直接"拆"成它内部的列表值,省掉一层嵌套,最终输出像 [ [123, 45.6], [789, 12.3] ] 这样的扁平数组。 Jackson @JsonValue 注解的核心作用 通常情况下,Jackson 在序列化一个 Java

利用 @JsonValue 注解,Jackson 可以把一个对象直接"拆"成它内部的列表值,省掉一层嵌套,最终输出像 [ [123, 45.6], [789, 12.3] ] 这样的扁平数组。

Jackson @JsonValue 注解的核心作用

通常情况下,Jackson 在序列化一个 Java 对象时,默认会把它的所有字段作为键值对输出为一个 JSON 对象。但在某些场景中,我们不希望 DataPoint 被包成 { "dataPoint": [...] } 的形式,而是希望它本身直接等价于内部的二维数值列表——即每个 DataPoint 实例应该被序列化为一个长度为 2 的数组 [long, double],并作为 dataPoint 数组中的元素。

解决方案非常简洁:只需在承载数据的字段或对应的 getter 方法上添加 @JsonValue 注解即可。

public class DataPoint {
    private final List data;

    public DataPoint(long date, double counts) {
        this.data = List.of(date, counts);
    }

    @JsonValue  // ← 核心注解:标记这个方法是对象转 JSON 时的唯一值表示
    public List getData() {
        return data;
    }
}

使用 @JsonValue 的注意事项:

  • @JsonValue 只能标注一个非 void 且非 void 泛型的 public 方法或字段(推荐用 getter);
  • 如果标注两个,Jackson 会直接报错;
  • 该注解只管序列化(Java → JSON),反序列化(JSON → Java)需要配合 @JsonCreator 或默认构造器加 setter。上面代码中的 data 是只读 final 字段,因此建议补充一个带参数的 @JsonCreator 构造器来支持反序列化;
  • List> 在序列化时类型不够明确,建议使用 List 或更稳妥的 List——因为 long 和 double 都属于 Number。

完整示例:同时支持序列化与反序列化

public class DataPoint {
    private final List data;

    public DataPoint(long date, double counts) {
        this.data = List.of(date, counts);
    }

    @JsonCreator
    public DataPoint(@JsonProperty("data") List data) {
        if (data == null || data.size() != 2) {
            throw new IllegalArgumentException("DataPoint requires exactly 2 numbers");
        }
        this.data = data;
    }

    @JsonValue
    public List getData() {
        return data;
    }
}

配置完成后,Entry 类无需任何修改,Jackson 即可输出预期的 JSON 结构:

{
  "name": "20070480",
  "dataPoint": [
    [1681792679186, 1096.0],
    [1681792680186, 1147.0]
  ]
}

@JsonValue 的实质与优势

@JsonValue 是 Jackson 提供的一种轻量级声明式机制,专门用于将对象“降维”为一个简单的 JSON 值(例如数组、字符串或数字)。对于“对象本身就是数据元组”的场景,它尤为合适,既无需编写自定义序列化器,又兼顾了简洁性与可维护性。