You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何使用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.21 08:12:09