跳转到主内容
websoft网络软件专家 - 深耕网络技术,打造实用软件!

如何使用 Gson 将含重复键的 JSON 数组聚合为带对象列表的目标结构

本文介绍在无法修改原始 js on 的前提下,利用 gson 实现“按 `action` 字段归并多个 `myobject` 为单个列表”的反序列化转换方案,通过两阶段解析(先转原始模型,再手动聚合)达成目标输出。 在实际 JSON 数据集成场景中,常遇到结构不规范但又不可修改的输入源——例如同一数组中多个对象均携带相同 action 键(如 "create"),且各自关联独立的 myObject 子对象。此时若期望将所有同 action 的 myObject 聚合为一个列表(而非逐个映射为独立对象),标准反序列化器(如 Gson 或 Jackson)无法直接支持,因为其默认行为是按字段一对一绑定,不具备跨对象聚合能力。 解决该问题的核心思路是 解耦解析与建模 :不强行让单一 Java 类同时兼容输入结构与输出结构,而是分两步处理: 解析阶段 :定义轻量级原始模型(OriginalModel),忠实映射输入 JSON 的扁平数组结构; 转换阶段 :在内存中按 action 分组聚合 myObject,构造符合目标格式的 TransformedModel; 序列化阶段 :将转换后的对象重新序列化为所需 JSON。 以下是完整可运行的实现示例(基于 Gson 2.10+):
import com.google.gson.Gson; import com.google.gson.reflect.TypeToken; import java.lang.reflect.Type; import java.util.*; // 原始 JSON 对应的结构(一一映射输入) static class OriginalModel { String action; MyObjectData myObject; } // 目标输出对应的结构(action + myObject 列表) static class TransformedModel { String action; List myObject; TransformedModel(String action, List myObject) { this.action = action; this.myObject = myObject; } } // myObject 内部数据结构 static class MyObjectData { String name; String description; }
执行转换逻辑: Find JSON Path Online Easily find JSON paths within JSON objects using our intuitive Json Path Finder 下载
Gson gson = new Gson(); String json = "[\n" + " {\"myObject\": {\"name\": \"foo\", \"description\": \"bar\"}, \"action\": \"create\"},\n" + " {\"myObject\": {\"name\": \"baz\", \"description\": \"qux\"}, \"action\": \"create\"}\n" + "]"; // Step 1: 解析为原始模型列表 Type originalType = new TypeToken>() {}.getType(); List originalList = gson.fromJson(json, originalType); // Step 2: 按 action 分组聚合 myObject(保持原始顺序) Map> grouped = new LinkedHashMap<>(); for (OriginalModel item : originalList) { if (item.action != null && item.myObject != null) { grouped.computeIfAbsent(item.action, k -> new ArrayList<>()).add(item.myObject); } } // Step 3: 构造目标模型列表 List transformedList = grouped.entrySet().stream() .map(entry -> new TransformedModel(entry.getKey(), entry.getValue())) .toList(); // Step 4: 序列化为最终 JSON(即所需输出格式) String resultJson = gson.toJson(transformedList); System.out.println(resultJson); // 输出:[{"action":"create","myObject":[{"name":"foo","description":"bar"},{"name":"baz","description":"qux"}]}]
✅ 关键注意事项 : LinkedHashMap 确保 action 分组顺序与输入数组中首次出现顺序一致; 所有嵌套类建议声明为 static,避免隐式持有外部类引用导致序列化异常; 若输入 JSON 中存在多种 action 值(如 "create" 和 "update"),本方案会自动生成多个 TransformedModel 实例,完全符合语义; 此方法 不依赖任何特殊注解或反序列化配置 (如 @JsonAnySetter 或 ACCEPT_SINGLE_VALUE_AS_ARRAY),规避了配置失效风险,具备强健性与可调试性; 如需 Jackson 实现,逻辑完全一致,仅需替换为 ObjectMapper + TypeReference> 即可。 该方案以清晰的职责分离和显式的转换逻辑,兼顾可读性、可维护性与兼容性,是处理“非标准 JSON 聚合需求”的推荐实践。

相关文章