本文讲解如何利用 Jackson 直接解析类似 "result": [[123,"FOO","BAR",456], [...]] 的嵌套数组结构,无需编写自定义反序列化器,只需正确声明字段类型(如 Object[][] 或 List>)即可实现高效、类型安全的映射。
处理动态结构的 JSON 数据时,开发者常会碰到一个棘手场景——result 字段是“数组的数组”,即二维数组,且内部元素类型不统一,比如同时包含数字和字符串。许多开发者第一反应是需要编写自定义 JsonDeserializer。事实上,Jackson 原生就支持灵活映射这类集合与数组类型,关键在于 DTO 中的字段声明要正确。
下面提供一个完整可用的 DTO 示例,一看便知如何操作:
@JsonIgnoreProperties(ignoreUnknown = true)
public class TestDto {
@JsonProperty("status")
private Integer status;
// 方案一:使用 Object[][] —— 适合已知固定维度、追求轻量和性能的场景
@JsonProperty("result")
private Object[][] result;
// 方案二(推荐):使用 List> —— 更具扩展性,支持动态长度、便于遍历和函数式操作
// @JsonProperty("result")
// private List> result;
// Getter & Setter
public Integer getStatus() { return status; }
public void setStatus(Integer status) { this.status = status; }
public Object[][] getResult() { return result; }
public void setResult(Object[][] result) { this.result = result; }
// 若选用 List>,则对应添加如下方法:
/*
public List> getResult() { return result; }
public void setResult(List> result) { this.result = result; }
*/
}
实际配合 ObjectMapper 解析时,代码也非常简洁:
ObjectMapper mapper = new ObjectMapper();
String json = "{\n" +
" \"status\": 200,\n" +
" \"result\": [\n" +
" [123, \"FOO\", \"BAR\", 456],\n" +
" [789, \"BAZ\", \"QUX\", 101]\n" +
" ]\n" +
"}";
TestDto dto = mapper.readValue(json, TestDto.class);
System.out.println("Status: " + dto.getStatus()); // 输出: Status: 200
// 遍历二维结果(以 Object[][] 为例)
for (Object[] row : dto.getResult()) {
System.out.println(Arrays.toString(row));
// 输出: [123, FOO, BAR, 456] 和 [789, BAZ, QUX, 101]
}
以下是几个值得注意的细节:
- 使用
Object[][]时,要求 JSON 中的 result 严格是二维数组。如果某一行是 null 或根本不是数组,Jackson 会直接抛出JsonMappingException。换句话说,它的容错性较低,适合数据格式极其固定的场景。 - 改用
List会健壮很多。空数组- >
[]或者字段缺失(配合@JsonInclude(Include.NON_NULL))都能自然处理,而且遍历和函数式操作更灵活,是日常开发中更推荐的做法。 - 如果对每一行内元素的类型有明确预期——比如知道每行就是 [Integer, String, String, Integer] 这样固定的结构——那就别偷懒用泛型 Object 了。定义一个专用的内嵌类(比如
RecordItem),类型安全直接拉满,代码可读性也更好。 - 最后一个小提醒:所有字段都建议加上
@JsonProperty显式标注,尤其是在字段名和 JSON key 不一致,或者你改了 Jackson 的命名策略时,避免出现明明字段对了却映射失败的尴尬。
总结一下:面对嵌套数组结构,优先试试 Jackson 内置的集合或数组类型——简单、可靠、不需要额外侵入。只有当你遇到字段动态键名、混合类型歧义、或需要上下文校验等复杂逻辑时,才需要考虑自己实现 JsonDeserializer。大多数情况下,两行声明就能搞定。
