使用Jackson JsonParser区分独立Customer与CustomerDocument输入的反序列化实现
实现方案
核心思路
通过自定义Jackson流式处理逻辑,直接操作JsonParser游标逐token判断输入类型,全程不加载全量数据:
- 优先通过根对象的特征字段(
isA、customerList)区分输入场景 - 识别为批量
CustomerDocument场景时,直接定位到customerList数组节点,逐个反序列化数组内的Customer对象,无需加载整个数组到内存 - 识别为单个
Customer场景时,直接反序列化根节点即可,单个对象体积极小,无内存压力
代码实现
无需新增额外实体类,仅需实现一个流式处理工具类即可:
import com.fasterxml.jackson.core.JsonParser; import com.fasterxml.jackson.core.JsonToken; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; import java.io.IOException; import java.io.InputStream; import java.io.BufferedInputStream; import java.util.function.Consumer; public class CustomerProcessor { private final ObjectMapper objectMapper = new ObjectMapper(); /** * 自动兼容两种输入场景,流式处理Customer对象 * @param input 支持String、byte[]、InputStream等多种输入类型 * @param customerHandler 单个Customer的处理回调,处理完即回收内存 * @throws IOException 解析异常 */ public void process(Object input, Consumer<Customer> customerHandler) throws IOException { // 输入为InputStream时提前包装为支持标记重置的缓冲流,避免根节点元数据读取失败 if (input instanceof InputStream inputStream && !(inputStream instanceof BufferedInputStream)) { input = new BufferedInputStream(inputStream, 1024 * 1024); // 预留1MB缓存存储外层元数据足够 ((BufferedInputStream) input).mark(1024 * 1024); } try (JsonParser parser = objectMapper.createParser(input)) { // 定位到根对象起始位置 if (parser.nextToken() != JsonToken.START_OBJECT) { throw new IllegalArgumentException("输入不是合法JSON对象"); } // 读取第一个字段判断输入类型 if (parser.nextToken() != JsonToken.FIELD_NAME) { return; // 空对象直接返回 } String firstField = parser.getCurrentName(); // 匹配到批量文档标识,走流式批量处理逻辑 if ("isA".equals(firstField) || "customerList".equals(firstField)) { // 先跳过isA字段的取值 if ("isA".equals(firstField)) { parser.nextToken(); parser.skipChildren(); // 遍历找到customerList字段 while (parser.nextToken() == JsonToken.FIELD_NAME) { if ("customerList".equals(parser.getCurrentName())) break; parser.nextToken(); parser.skipChildren(); } } // 定位到customerList数组起始位置 if (parser.nextToken() != JsonToken.START_ARRAY) { throw new IllegalArgumentException("customerList字段不是合法数组"); } // 流式逐个处理数组元素,不加载全量数据 while (parser.nextToken() != JsonToken.END_ARRAY) { Customer customer = parser.readValueAs(Customer.class); customerHandler.accept(customer); } return; } // 单Customer场景,直接读取整个根对象反序列化 JsonNode rootNode = parser.readValueAsTree(); Customer customer = objectMapper.treeToValue(rootNode, Customer.class); customerHandler.accept(customer); } } }
使用示例
public class Test { public static void main(String[] args) throws IOException { CustomerProcessor processor = new CustomerProcessor(); // 1. 处理单个Customer输入 String singleJson = "{\"id\":1,\"name\":\"张三\",\"phone\":\"13xxxxxxxxx\"}"; processor.process(singleJson, customer -> { // 自定义处理逻辑 System.out.println("处理单个用户:" + customer.getName()); }); // 2. 处理批量CustomerDocument输入 String batchJson = "{\"isA\":\"CustomerDocument\",\"createTime\":\"2024-01-01\",\"customerList\":[{\"id\":1,\"name\":\"张三\"},{\"id\":2,\"name\":\"李四\"}]}"; processor.process(batchJson, customer -> { // 内存中仅保留当前处理的单个Customer对象,支持百万级以上数据量处理 System.out.println("批量处理用户:" + customer.getName()); }); } }
内容的提问来源于stack exchange,提问作者BATMAN_2008
相关产品推荐
相关产品推荐

