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

使用Retrofit/OkHttp解析嵌套JSON:无需大量POJO的简便方法

针对Retrofit解析嵌套JSON直接提取元素的方案

嘿,我太懂这种为了几层嵌套JSON写一堆POJO的麻烦了——完全是冗余代码!针对你的需求,其实有几个轻量的方案,不用定义一堆实体类就能直接提取你需要的元素,下面给你拆解一下:

1. 用Gson的JsonObject直接解析(最直观)

Retrofit默认集成Gson,所以你可以直接把接口的返回类型改成Call<JsonObject>,这样就能在回调里逐层定位到你需要的字段,不用提前定义任何POJO。

举个针对你提供的JSON的代码例子(Java版):

// 定义Retrofit接口
public interface DealsApi {
    @GET("your-api-endpoint")
    Call<JsonObject> getDeals();
}

// 发起请求并解析
dealsApi.getDeals().enqueue(new Callback<JsonObject>() {
    @Override
    public void onResponse(Call<JsonObject> call, Response<JsonObject> response) {
        if (response.isSuccessful() && response.body() != null) {
            // 逐层获取嵌套对象
            JsonObject dealsViewModel = response.body().getAsJsonObject("DealsViewModel");
            JsonObject countryDeals = dealsViewModel.getAsJsonObject("CountryDealsViewModel");
            
            // 提取单个字符串字段
            String cultureCountry = countryDeals.get("CultureCountry").getAsString();
            String cultureLanguage = countryDeals.get("CultureLanguage").getAsString();
            
            // 提取数组里的元素
            JsonArray dealsPageInfoArray = countryDeals.getAsJsonArray("DealsPageInfo");
            for (JsonElement element : dealsPageInfoArray) {
                JsonObject dealItem = element.getAsJsonObject();
                String displayName = dealItem.get("DisplayName").getAsString();
                String startDate = dealItem.get("StartDate").getAsString();
                // 这里就可以直接用这些数据做业务处理了
            }
        }
    }

    @Override
    public void onFailure(Call<JsonObject> call, Throwable t) {
        // 处理请求失败逻辑
        t.printStackTrace();
    }
});

如果是Kotlin,代码会更简洁,借助Gson的扩展函数可以少写不少样板代码:

interface DealsApi {
    @GET("your-api-endpoint")
    suspend fun getDeals(): JsonObject
}

// 调用(协程环境下)
try {
    val response = dealsApi.getDeals()
    val countryDeals = response.getAsJsonObject("DealsViewModel")
        .getAsJsonObject("CountryDealsViewModel")
    
    val cultureCountry = countryDeals["CultureCountry"].asString
    val cultureLanguage = countryDeals["CultureLanguage"].asString
    
    val dealsPageInfo = countryDeals.getAsJsonArray("DealsPageInfo")
    dealsPageInfo.forEach { element ->
        val deal = element.asJsonObject
        val displayName = deal["DisplayName"].asString
        val startDate = deal["StartDate"].asString
        // 处理数据
    }
} catch (e: Exception) {
    e.printStackTrace()
}

2. 流式解析(适合超大JSON)

如果你的JSON体积特别大,用JsonObject会把整个JSON加载到内存里,这时候可以用Gson的JsonReader或者OkHttp的ResponseBody来流式解析,只提取你需要的字段,避免内存占用过高。

举个简单的Java例子:

@GET("your-api-endpoint")
Call<ResponseBody> getDeals();

// 调用解析
dealsApi.getDeals().enqueue(new Callback<ResponseBody>() {
    @Override
    public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {
        if (response.isSuccessful() && response.body() != null) {
            try (JsonReader reader = new JsonReader(response.body().charStream())) {
                reader.beginObject();
                while (reader.hasNext()) {
                    if (reader.nextName().equals("DealsViewModel")) {
                        reader.beginObject();
                        while (reader.hasNext()) {
                            if (reader.nextName().equals("CountryDealsViewModel")) {
                                reader.beginObject();
                                while (reader.hasNext()) {
                                    String name = reader.nextName();
                                    switch (name) {
                                        case "CultureCountry":
                                            String cultureCountry = reader.nextString();
                                            // 处理这个字段
                                            break;
                                        case "CultureLanguage":
                                            String cultureLanguage = reader.nextString();
                                            // 处理这个字段
                                            break;
                                        case "DealsPageInfo":
                                            reader.beginArray();
                                            while (reader.hasNext()) {
                                                reader.beginObject();
                                                while (reader.hasNext()) {
                                                    String itemName = reader.nextName();
                                                    if (itemName.equals("DisplayName")) {
                                                        String displayName = reader.nextString();
                                                    } else if (itemName.equals("StartDate")) {
                                                        String startDate = reader.nextString();
                                                    } else {
                                                        reader.skipValue(); // 跳过不需要的字段
                                                    }
                                                }
                                                reader.endObject();
                                            }
                                            reader.endArray();
                                            break;
                                        default:
                                            reader.skipValue(); // 跳过不需要的嵌套字段
                                    }
                                }
                                reader.endObject();
                            } else {
                                reader.skipValue();
                            }
                        }
                        reader.endObject();
                    } else {
                        reader.skipValue();
                    }
                }
                reader.endObject();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    @Override
    public void onFailure(Call<ResponseBody> call, Throwable t) {
        t.printStackTrace();
    }
});

这种方式虽然代码多一点,但内存友好,适合处理大体积JSON。

小总结

  • 如果只是临时提取几个字段,或者JSON结构简单,用JsonObject直接解析是最便捷的选择,不用额外定义任何实体类。
  • 如果JSON体积很大,怕内存溢出,就用流式解析,只加载你需要的部分。
  • 要是之后业务需要用到的字段变多,维护性要求高,还是建议写对应的POJO类——毕竟代码可读性和可维护性更重要。

内容的提问来源于stack exchange,提问作者Shawn.Y

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.27 03:52:30