在 Java 專案中,後端常回傳統一結構的 JSON:{"data": [...], "info": "", "status": 0},其中 data 可能是任意類型的列表(如 List<User>、List<Product>)。若為每種類型寫死對應的 Wrapper 類,會導致程式碼膨脹且難以維護。本文介紹利用 Gson 的 JsonElement 與 TypeToken 實現通用解析策略。
先將整個回傳解析為通用的 ApiResponse<JsonElement>,再根據業務上下文(如 API 端點、狀態碼)決定將 data 反序列化為具體類型。
public class ApiResponse<T> {
private T data;
private String info;
private int status;
// getter/setter 省略
}
Gson gson = new Gson();
String json = "{\"data\":[{\"id\":1,\"name\":\"A\"}],\"info\":\"ok\",\"status\":0}";
// 解析為包含 JsonElement 的通用回應
Type responseType = new TypeToken<ApiResponse<JsonElement>>(){}.getType();
ApiResponse<JsonElement> response = gson.fromJson(json, responseType);
// 此時 response.getData() 是 JsonElement(可能是 JsonArray 或 JsonObject)
JsonElement dataElement = response.getData();
// 假設此 API 應回傳 List<User>
if (dataElement.isJsonArray()) {
Type listType = new TypeToken<List<User>>(){}.getType();
List<User> userList = gson.fromJson(dataElement, listType);
// 業務邏輯使用 userList
} else if (dataElement.isJsonObject()) {
// 單一物件情況
User user = gson.fromJson(dataElement, User.class);
}
public class GsonUtils {
private static final Gson GSON = new Gson();
public static <T> ApiResponse<T> parseResponse(String json, Class<T> dataClass) {
// 先解析原始 JsonElement
ApiResponse<JsonElement> raw = GSON.fromJson(json, new TypeToken<ApiResponse<JsonElement>>(){}.getType());
// 再轉換 data 為目標類型
T data = GSON.fromJson(raw.getData(), dataClass);
return new ApiResponse<T>(data, raw.getInfo(), raw.getStatus());
}
public static <T> ApiResponse<List<T>> parseListResponse(String json, Class<T> itemClass) {
ApiResponse<JsonElement> raw = GSON.fromJson(json, new TypeToken<ApiResponse<JsonElement>>(){}.getType());
Type listType = TypeToken.getParameterized(List.class, itemClass).getType();
List<T> list = GSON.fromJson(raw.getData(), listType);
return new ApiResponse<List<T>>(list, raw.getInfo(), raw.getStatus());
}
}
// 使用範例
ApiResponse<List<User>> resp = GsonUtils.parseListResponse(json, User.class);
List<User> users = resp.getData();
若 API 數量極大且效能敏感,可編寫 TypeAdapter<ApiResponse<T>> 在單次解析中完成多態反序列化,但程式碼複雜度較高,一般專案上述兩階段法足夠。
data 為 null 時,JsonElement 為 JsonNull,需先判斷 isJsonNull()。TypeAdapter<Date>。data 有時是陣列、有時是單物件,解析前必須用 isJsonArray()/isJsonObject() 分流。利用 JsonElement 作為中介,配合 TypeToken 進行二次反序列化,是 Gson 處理「固定外層、不定內層」JSON 結構的標準最佳實務。既避免了大量 Wrapper 類,又保持型別安全與程式碼可讀性。