如何使用Gson解析含同键不同类型的JSON数据(Retrofit2场景)
解决Retrofit2+Gson解析同名不同类型
data字段的问题 这问题我之前做项目时也踩过坑!核心困惑点在于JSON里不同层级的同名data字段对应了不同数据类型:外层的data是包含分页信息的对象,内层的data是机构列表的数组。其实只要理清Gson的解析逻辑,就能轻松解决,下面给你分情况说明:
方案1:正确定义实体类(最简单直接)
Gson是按JSON层级逐层解析的,不同层级的同名字段完全是独立的,不会互相干扰。所以只要让你的Java实体类结构和JSON结构严格对应,就能直接解析成功。
步骤1:定义对应层级的实体类
// 最外层的API响应类 public class ApiResponse<T> { private int code; private T data; // 这里的T对应外层的data对象类型 } // 外层data对应的分页数据类 public class PageData { private int totalPages; private int pageSize; private int page; private List<Org> data; // 这里的data对应内层的数组类型 } // 机构信息实体类 public class Org { private double hot; private int orgid; private int total; private String logo; private String org_name; }
步骤2:配置Retrofit并发起请求
// 定义API接口 public interface OrgApiService { @GET("your/api/path") // 替换成你的实际接口路径 Call<ApiResponse<PageData>> getOrgList(); } // 创建Retrofit实例并发起请求 Retrofit retrofit = new Retrofit.Builder() .baseUrl("your/base/url") // 替换成你的基础URL .addConverterFactory(GsonConverterFactory.create()) .build(); OrgApiService apiService = retrofit.create(OrgApiService.class); apiService.getOrgList().enqueue(new Callback<ApiResponse<PageData>>() { @Override public void onResponse(Call<ApiResponse<PageData>> call, Response<ApiResponse<PageData>> response) { if (response.isSuccessful() && response.body() != null) { ApiResponse<PageData> apiResp = response.body(); if (apiResp.getCode() == 0) { // 服务端返回成功 PageData pageInfo = apiResp.getData(); List<Org> orgList = pageInfo.getData(); // 在这里处理你的机构列表数据 } } } @Override public void onFailure(Call<ApiResponse<PageData>> call, Throwable t) { // 处理请求失败逻辑 t.printStackTrace(); } });
这个方案完全不需要额外配置Gson,因为Gson会自动根据层级映射字段,不同层级的data字段因为所属的父对象不同,不会出现类型冲突。
方案2:自定义TypeAdapter(应对特殊场景)
如果你的场景更复杂(比如同一层级的data字段有时候返回对象、有时候返回数组),那可以通过自定义Gson的TypeAdapter来动态处理类型转换。
示例代码:
public class DynamicDataAdapter extends TypeAdapter<Object> { private final Gson gson = new Gson(); @Override public void write(JsonWriter out, Object value) throws IOException { // 如果需要序列化数据,在这里实现逻辑 gson.toJson(value, value.getClass(), out); } @Override public Object read(JsonReader in) throws IOException { JsonToken token = in.peek(); // 根据当前JSON节点的类型动态解析 if (token == JsonToken.BEGIN_ARRAY) { return gson.fromJson(in, new TypeToken<List<Org>>() {}.getType()); } else if (token == JsonToken.BEGIN_OBJECT) { return gson.fromJson(in, PageData.class); } else { in.skipValue(); // 跳过未知类型的节点 return null; } } }
注册适配器到Gson:
Gson customGson = new GsonBuilder() .registerTypeAdapter(Object.class, new DynamicDataAdapter()) .create(); // 用自定义Gson创建Retrofit实例 Retrofit retrofit = new Retrofit.Builder() .baseUrl("your/base/url") .addConverterFactory(GsonConverterFactory.create(customGson)) .build();
总结
回到你的问题,因为data字段处于不同层级,方案1是最优解,简单且不易出错。只有当同一层级出现动态类型的同名字段时,才需要用到方案2的自定义适配器。
内容的提问来源于stack exchange,提问作者Jsonzsl
相关产品推荐
相关产品推荐

