如何使用GSON处理同一接口返回的两种不同格式的regions字段?
这问题我对接第三方API时真的碰到过,两种返回格式确实容易搞混,用适配器来统一是绝佳方案!我给你一步步拆解怎么实现:
核心思路
本质就是把两种异构的API响应,转换为一个统一的内部模型,这样后续业务代码只需要处理这个统一模型,不用关心原始API的格式差异。适配器模式正好适配这种场景——做一层格式转换的中间层。
具体实现步骤(以Java为例,其他语言思路一致)
1. 定义统一的内部模型
先不管API返回什么格式,先确定我们业务代码需要的最终数据结构:
// 业务侧统一使用的区域模型 public class Region { private String id; private String name; // 构造器、getter、setter按需生成 public Region(String id, String name) { this.id = id; this.name = name; } // 省略getter、setter } // 统一的响应模型,包含业务需要的所有字段 public class UnifiedApiResponse { private String id; private String name; private List<Region> regions; public UnifiedApiResponse(String id, String name, List<Region> regions) { this.id = id; this.name = name; this.regions = regions; } // 省略getter、setter }
2. 处理原始API的两种格式
我们需要先能解析原始的两种JSON格式,这里提供两种思路:
方式一:用DTO匹配原始格式(类型安全)
先定义对应两种返回格式的DTO,让序列化框架自动匹配:
// 对应仅返回区域ID的格式 public class SimpleRegionApiResponse { private Data data; public static class Data { private String id; private String name; private List<String> regions; // 省略getter、setter } } // 对应返回完整区域对象的格式 public class FullRegionApiResponse { private Data data; public static class Data { private String id; private String name; private RegionWrapper regions; public static class RegionWrapper { private List<Region> data; // 省略getter、setter } // 省略getter、setter } }
方式二:用动态节点判断格式(更灵活)
如果API格式可能有变动,或者不想写太多DTO,可以先把JSON解析为通用的JsonNode,判断regions字段的类型:
ObjectMapper objectMapper = new ObjectMapper(); JsonNode root = objectMapper.readTree(rawJson); JsonNode regionsNode = root.path("data").path("regions"); if (regionsNode.isArray()) { // 是简单格式:直接取数组里的ID } else if (regionsNode.isObject()) { // 是完整格式:取对象里的data数组 } else { throw new IllegalArgumentException("不合法的regions格式"); }
3. 编写适配器类做统一转换
把两种格式的解析和转换逻辑封装到适配器里,对外暴露统一的转换方法:
import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; import java.util.ArrayList; import java.util.List; public class RegionResponseAdapter { private static final ObjectMapper objectMapper = new ObjectMapper(); // 对外统一的转换方法,输入原始JSON,输出统一模型 public static UnifiedApiResponse convert(String rawJson) throws JsonProcessingException { JsonNode root = objectMapper.readTree(rawJson); JsonNode dataNode = root.path("data"); String id = dataNode.path("id").asText(); String name = dataNode.path("name").asText(); JsonNode regionsNode = dataNode.path("regions"); List<Region> regions; if (regionsNode.isArray()) { // 处理简单格式:将ID列表转为Region对象(name设为null或空) regions = new ArrayList<>(); for (JsonNode idNode : regionsNode) { regions.add(new Region(idNode.asText(), null)); } } else if (regionsNode.isObject()) { // 处理完整格式:直接提取data数组转为Region列表 regions = objectMapper.convertValue(regionsNode.path("data"), List.class); } else { throw new IllegalArgumentException("API返回的regions字段格式不支持"); } return new UnifiedApiResponse(id, name, regions); } }
4. 使用示例
业务代码里直接调用适配器的转换方法,拿到统一模型后就可以正常处理了:
public class Demo { public static void main(String[] args) throws JsonProcessingException { // 简单格式的API返回 String simpleJson = "{ \"data\":{ \"id\":\"12345\", \"name\":\"Some Name\", \"regions\":[ \"r987\", \"r654\" ] } }"; UnifiedApiResponse simpleResult = RegionResponseAdapter.convert(simpleJson); System.out.println(simpleResult.getRegions()); // 完整格式的API返回 String fullJson = "{ \"data\":{ \"id\":\"12345\", \"name\":\"Some Name\", \"regions\":{ \"data\":[ { \"id\":\"r987\", \"name\":\"region 1\" }, { \"id\":\"r654\", \"name\":\"region 2\" } ] } } }"; UnifiedApiResponse fullResult = RegionResponseAdapter.convert(fullJson); System.out.println(fullResult.getRegions()); } }
额外提示
- 如果是Python/JavaScript这类动态语言,思路完全一致:先判断
regions的类型(数组/对象),再转换为统一的列表结构 - 可以在适配器里加入日志,方便排查格式异常问题
- 如果API有更多格式变种,可以在适配器里扩展判断逻辑,不影响业务代码
内容的提问来源于stack exchange,提问作者Fillipe Duoli
相关产品推荐
相关产品推荐

