首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 更多程式語言 >> 程式設計綜合問答

Gson 解析不定類型 data 列表的通用方案:利用 JsonElement 與 TypeToken 實現多態反序列化

     編輯:程式設計綜合問答

在 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 省略
}

步驟二:第一階段解析為 JsonElement

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();

替代方案:自訂 TypeAdapter(適用於極高效能場景)

若 API 數量極大且效能敏感,可編寫 TypeAdapter<ApiResponse<T>> 在單次解析中完成多態反序列化,但程式碼複雜度較高,一般專案上述兩階段法足夠。

常見坑點提醒

  • data 為 null 時,JsonElement 為 JsonNull,需先判斷 isJsonNull()。
  • 日期格式不一致時,建立 Gson 時註冊自訂 TypeAdapter<Date>。
  • 若後端 data 有時是陣列、有時是單物件,解析前必須用 isJsonArray()/isJsonObject() 分流。

總結

利用 JsonElement 作為中介,配合 TypeToken 進行二次反序列化,是 Gson 處理「固定外層、不定內層」JSON 結構的標準最佳實務。既避免了大量 Wrapper 類,又保持型別安全與程式碼可讀性。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved