本文详解如何使用 Jackson 直接解析形如 "result": [[123,"FOO","BAR",456], [123,"FOO","BAR",456]] 的嵌套数组,无需自定义反序列化器,通过泛型集合、原始二维数组或类型化列表即可优雅实现。
在实际开发中,尤其是对接第三方 API 或处理动态结构数据时,大家常常会遇到这种让人头疼的 JSON 结构:
{ "status": 200, "result": [ [123, "FOO", "BAR", 456], [123, "FOO", "BAR", 456] ]}这里的 result 是一个嵌套数组,元素类型混合(整数、字符串等),且行数不固定。如果仅用简单 DTO 声明 status 字段而忽略 result,反序列化就会失败,或者字段直接变成 null。
好消息是,Jackson 原生支持多种灵活方式解析这类嵌套数组,完全不用自定义反序列化器。下面按推荐度排序,介绍三种方案。
方案一:使用 List>(最推荐)
类型安全、可读性强,便于后续遍历与类型转换:
@JsonIgnoreProperties(ignoreUnknown = true)public class TestDto { @JsonProperty("status") private Integer status; @JsonProperty("result") private List> result; // 自动映射嵌套数组 // getters & setters public Integer getStatus() { return status; } public void setStatus(Integer status) { this.status = status; } public List> getResult() { return result; } public void setResult(List> result) { this.result = result; }}
✅ 优势:
- 支持任意长度嵌套数组;
- 每个内层数组自动转为 List
- 可配合 instanceof 或 NumberUtils 等工具做运行时类型判断与转换(如 ((Number) row.get(0)).intValue())。
方案二:使用 Object[][](简洁高效)
适用于对性能敏感、且不需频繁增删元素的场景:
@JsonProperty("result")private Object[][] result;调用示例:
TestDto dto = objectMapper.readValue(jsonString, TestDto.class);System.out.println(dto.getResult()[0][1]); // 输出 "FOO"
注意:Object[][] 在 Ja va 中是“不规则数组”的近似表示(每行长度可不同),但 Jackson 会确保其结构与 JSON 一致;若某行缺失字段,对应位置为 null。
方案三:使用 List
兼顾集合灵活性与数组访问效率:
@JsonProperty("result")private List访问方式:
for (Object[] row : dto.getResult()) { Integer id = ((Number) row[0]).intValue(); String code = (String) row[1]; // ...}关键注意事项
- 务必添加 @JsonProperty("result"):字段名与 JSON key 不一致时必须显式声明,否则 Jackson 默认按 Ja va 驼峰命名匹配(如 result → result 可省略,但建议显式标注以增强可维护性);
- 启用 DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY(可选):当服务端偶发返回单个数组(而非数组嵌套)时,此配置可兼容 ["a","b"] → result 单元素列表;
- 避免 List
- > 等强类型泛型
- > 将导致 JsonMappingException —— Jackson 无法将数字 123 强转为 String。
综上,对于动态、混合类型的嵌套数组,优先选用 List>,它在可读性、扩展性与 Jackson 兼容性之间取得最佳平衡,是标准实践中的首选方案。