
本文介绍如何使用 Jackson 的 @JsonValue 注解,让自定义对象(如 DataPoint)在序列化时直接输出为其内部列表内容,而非嵌套 JSON 对象,从而生成紧凑的二维数组结构。
本文介绍如何使用 jackson 的 `@jsonvalue` 注解,让自定义对象(如 `datapoint`)在序列化时直接输出为其内部列表内容,而非嵌套 json 对象,从而生成紧凑的二维数组结构。
在构建符合特定 JSON Schema 的数据结构时,常需将 Java 对象“扁平化”为原始数组形式。例如,目标 JSON 要求 dataPoint 字段为 [ [long, double], [long, double] ] 这样的二维数组,而非 { "dataPoint": [1681792679186, 1096.0] } 的对象包装结构。
问题根源在于:默认情况下,Jackson 将 DataPoint 视为一个普通 POJO,会将其所有字段(或 getter 返回值)作为键值对序列化。即使 DataPoint 内部仅维护一个 List<?> data,它仍会被序列化为 "data": [...] 的属性,导致嵌套层级过深。
解决方案非常简洁——使用 @JsonValue 注解标记 data 字段或其 getter 方法。该注解告诉 Jackson:此值即为该对象的唯一序列化表示,忽略其他字段和对象外壳,直接输出其内容。
public class DataPoint {
private final List<Object> data;
public DataPoint(long date, double counts) {
this.data = List.of(date, counts);
}
@JsonValue // ✅ 关键注解:使 data 成为整个对象的序列化结果
public List<Object> getData() {
return data;
}
}⚠️ 注意事项:
- @JsonValue 方法必须返回非 void 类型,且只能在一个类中出现一次;
- 推荐使用 getter 方法(而非字段)标注,以保持封装性;
- 若 data 为 List<?>,建议明确类型(如 List<Object> 或 List<Number>),避免泛型擦除带来的运行时不确定性;
- 此方案仅影响序列化(Java → JSON);反序列化(JSON → Java)需配合 @JsonCreator 和构造器参数绑定(本文未涉及,但实际项目中建议一并实现)。
最终,结合 Entry 类(保持原结构不变),序列化结果将严格匹配预期格式:
{
"name": "20070480",
"dataPoint": [
[1681792679186, 1096.0],
[1681792680186, 1147.0]
]
}无需编写自定义 JsonSerializer,也无需修改顶层数据结构——@JsonValue 是 Jackson 提供的轻量、标准且语义清晰的解法,适用于任何需“对象即值”的场景。

















