如何使用Retrofit解析含嵌套对象及动态Key的JSON?
Got it, let's break this down into two clear parts: fetching the value of key3 from the nested object, and handling that dynamic value2 key. Here's how to tackle both with Retrofit (we'll use Gson as the converter since it's the most common choice):
key3 value This is straightforward—you just need to define data classes that mirror the JSON structure, including the nested key2 object.
Kotlin Example
// Top-level response data class data class ApiResponse( val key1: String, val key2: Key2Content, // We'll handle the dynamic key in the next section val dynamicData: Map<String, ActualData> = emptyMap() ) // Nested class for key2's content data class Key2Content( val key3: String, val key4: String ) // Define this if you know the structure of the "actual data" data class ActualData( // Add fields matching your actual data, e.g.: // val id: Int, // val content: String )
Java Example
public class ApiResponse { private String key1; private Key2Content key2; private Map<String, ActualData> dynamicData = new HashMap<>(); // Getters and setters public String getKey1() { return key1; } public void setKey1(String key1) { this.key1 = key1; } public Key2Content getKey2() { return key2; } public void setKey2(Key2Content key2) { this.key2 = key2; } public Map<String, ActualData> getDynamicData() { return dynamicData; } public void setDynamicData(Map<String, ActualData> dynamicData) { this.dynamicData = dynamicData; } } public class Key2Content { private String key3; private String key4; // Getters and setters public String getKey3() { return key3; } public void setKey3(String key3) { this.key3 = key3; } public String getKey4() { return key4; } public void setKey4(String key4) { this.key4 = key4; } } public class ActualData { // Match your actual data fields here }
Once you have these classes, Retrofit + Gson will automatically parse key3 for you. You can access it like this (Kotlin example):
val response = apiService.getResponse().body() response?.let { val key3Value = it.key2.key3 // That's your value2! }
value2 key Since value2 is a dynamic key (it could change name), we need a way to catch any unknown top-level keys. Here are two reliable approaches:
Option 1: Use a Map to catch dynamic keys
If you know the structure of the "actual data", define your top-level class with a Map that will hold all dynamic keys (like value2) and their corresponding data. This works out of the box with Gson.
In the examples above, we already included dynamicData: Map<String, ActualData>—Gson will automatically map any unknown top-level keys to this map. You can access the data like this:
response?.dynamicData?.forEach { (dynamicKey, actualData) -> // dynamicKey could be "value2" or any other dynamic name // actualData is the parsed object of your actual data structure }
Option 2: Use @JsonAnySetter for more control
If you want explicit control over how dynamic keys are handled, use Gson's @JsonAnySetter annotation. This lets you define a method that will be called for every unknown key in the JSON.
Kotlin Example
data class ApiResponse( val key1: String, val key2: Key2Content, private val dynamicEntries: MutableMap<String, ActualData> = mutableMapOf() ) { @JsonAnySetter fun addDynamicEntry(key: String, value: ActualData) { dynamicEntries[key] = value } // Helper method to get all dynamic data fun getDynamicData(): Map<String, ActualData> = dynamicEntries }
Java Example
public class ApiResponse { private String key1; private Key2Content key2; private Map<String, ActualData> dynamicEntries = new HashMap<>(); @JsonAnySetter public void addDynamicEntry(String key, ActualData value) { dynamicEntries.put(key, value); } // Getter for dynamic data public Map<String, ActualData> getDynamicEntries() { return dynamicEntries; } // Other getters/setters }
If you don't know the actual data structure
If you have no idea what the "actual data" looks like, replace ActualData with JsonElement (from Gson). This lets you manually parse the raw JSON later:
private val dynamicEntries: MutableMap<String, JsonElement> = mutableMapOf()
Then you can convert the JsonElement to a specific object when needed:
val gson = Gson() val actualData = gson.fromJson(dynamicEntries["value2"], ActualData::class.java)
Don't forget to add the Gson converter to your Retrofit setup. First, add the dependencies (for Gradle):
// Retrofit core implementation 'com.squareup.retrofit2:retrofit:2.9.0' // Gson converter implementation 'com.squareup.retrofit2:converter-gson:2.9.0'
Then create your Retrofit instance and API service:
Kotlin Example
interface ApiService { @GET("your-endpoint-path") suspend fun getResponse(): Response<ApiResponse> } // Initialize Retrofit val retrofit = Retrofit.Builder() .baseUrl("https://your-base-url.com/") .addConverterFactory(GsonConverterFactory.create()) .build() val apiService = retrofit.create(ApiService::class.java)
Java Example
public interface ApiService { @GET("your-endpoint-path") Call<ApiResponse> getResponse(); } // Initialize Retrofit Retrofit retrofit = new Retrofit.Builder() .baseUrl("https://your-base-url.com/") .addConverterFactory(GsonConverterFactory.create()) .build(); ApiService apiService = retrofit.create(ApiService.class);
That's it! You can now fetch key3 easily and handle any dynamic top-level keys in your JSON response.
内容的提问来源于stack exchange,提问作者Raviteja

