Jackson使用JsonParser反序列化时跳过首组键值对如何解决?
解决方案
核心思路
废弃原有的「试错反序列化+异常分支判断」逻辑,改用Jackson流式API(JsonParser)先做前置格式判定,全程不提前消费不可回溯的流节点,同时满足两种格式的反序列化要求,且不会全量加载大数组。
具体实现步骤
- 第一步:将输入流包装为
JsonParser,首先校验顶层结构为JSON对象,创建完成后立即标记流的起始位置,方便后续回溯 - 第二步:遍历顶层对象的所有字段名,同步做两个处理:
- 遇到
@context这类公共字段直接读取值存储,避免后续丢失 - 检测是否存在
customerList字段,直接判定JSON格式类型
- 遇到
- 第三步:分支处理
- 若判定为
CustomerDocument格式:定位到customerList的数组起始位置后,循环遍历数组节点,逐个反序列化为Customer对象,处理完一个立即释放内存,全程不会加载整个数组 - 若判定为单个
Customer格式:直接回溯到流起始位置,反序列化出完整的Customer对象,提前读取到的公共字段(如@context)可直接赋值到对象中
- 若判定为
代码示例
public void deserialize(InputStream inputStream, ObjectMapper objectMapper) throws IOException { try (JsonParser parser = objectMapper.getFactory().createParser(inputStream)) { // 标记流起始位置,用于后续回溯 if (parser.isMarkSupported()) { parser.mark(Integer.MAX_VALUE); } // 定位到顶层对象起始 if (parser.nextToken() != JsonToken.START_OBJECT) { throw new IllegalArgumentException("输入JSON格式非法"); } Object context = null; boolean isCustomerDocument = false; // 遍历顶层字段先做格式判定和公共字段读取 while (parser.nextToken() != JsonToken.END_OBJECT) { String fieldName = parser.getCurrentName(); parser.nextToken(); // 移动到字段值位置 if ("@context".equals(fieldName)) { // 提前读取公共字段存储 context = parser.readValueAs(Object.class); } else if ("customerList".equals(fieldName)) { isCustomerDocument = true; // 判定为数组格式,直接进入逐元素处理逻辑 if (parser.currentToken() == JsonToken.START_ARRAY) { while (parser.nextToken() != JsonToken.END_ARRAY) { // 逐个反序列化Customer,不存储全量数组 Customer customer = parser.readValueAs(Customer.class); // 这里直接处理单条customer,比如写入数据库/发送队列等 processSingleCustomer(customer, context); } } // 数组处理完直接跳出循环,无需读取剩余顶层字段 break; } else { // 其他字段暂不处理,后续反序列化时自动读取 parser.skipChildren(); } } // 走单个Customer反序列化逻辑 if (!isCustomerDocument) { // 回溯到流起始位置 parser.reset(); Customer customer = objectMapper.readValue(parser, Customer.class); // 赋值提前读取的@context customer.setContext(context); processSingleCustomer(customer, context); } } }
方案优势
- 不用异常做流程控制,逻辑更稳定可靠
- 全程流式处理,
customerList数组无论多大都不会占用过多内存 - 不需要额外定义
CustomerDocument或CustomerList包装类 - 所有公共字段如
@context都会被提前捕获,不会出现丢失问题
内容的提问来源于stack exchange,提问作者BATMAN_2008
相关产品推荐
相关产品推荐

