知識庫 / JSON RSS 訂閱

使用 Gson 將 JSON 轉換為 Map

JSON
HongKong
6
09:55 PM · Dec 05 ,2025

1. 簡介

在本快速教程中,我們將學習如何使用 Google 的 Gson 將 JSON 字符串轉換為 Map

我們將看到三種不同的方法來實現這一目標,並討論它們的優缺點,同時提供一些實際示例。

2. 傳遞 Map.class

一般來説,Gson 在其 Gson 類中提供以下 API,用於將 JSON 字符串轉換為對象

public <T> T fromJson(String json, Class<T> classOfT) throws JsonSyntaxException;

從簽名來看,很明顯第二個參數是JSON解析的目標對象類。在本例中,它應該為 Map.class

String jsonString = "{'employee.name':'Bob','employee.salary':10000}";
Gson gson = new Gson();
Map map = gson.fromJson(jsonString, Map.class);
Assert.assertEquals(2, map.size());
Assert.assertEquals(Double.class, map.get("employee.salary").getClass());

這種方法會根據每個屬性的值類型做出最佳猜測。

例如,數字會被轉換為 Doubletruefalse 轉換為 Boolean,對象則轉換為 LinkedTreeMap

如果存在重複的鍵,則轉換會失敗並拋出 JsonSyntaxException

並且,由於 type erasure,我們還無法配置這種轉換行為。因此,如果我們需要指定鍵或值類型,則需要採用不同的方法。

3. 使用 TypeToken

為了克服泛型類型中的類型擦除問題,Gson 提供了 API 的重載版本:

public <T> T fromJson(String json, Type typeOfT) throws JsonSyntaxException;

我們可以使用 Gson 的 TypeToken 來構建具有類型參數的 MapTypeToken 類返回一個 ParameterizedTypeImpl 實例,即使在運行時也能保留鍵和值的類型:

String jsonString = "{'Bob' : {'name': 'Bob Willis'},"
  + "'Jenny' : {'name': 'Jenny McCarthy'}, "
  + "'Steve' : {'name': 'Steven Waugh'}}";
Gson gson = new Gson();
Type empMapType = new TypeToken<Map<String, Employee>>() {}.getType();
Map<String, Employee> nameEmployeeMap = gson.fromJson(jsonString, empMapType);
Assert.assertEquals(3, nameEmployeeMap.size());
Assert.assertEquals(Employee.class, nameEmployeeMap.get("Bob").getClass());

現在,如果我們構建我們的 Map 類型為 Map<String, Object>,那麼解析器仍然會像之前章節中看到的默認行為。

當然,這仍然會回退到 Gson 來轉換原始數據類型。但是,這些原始數據類型也可以進行自定義。

4. 使用自定義 <em >JsonDeserializer</em >>

當我們需要對我們的 `Map>` 對象構造過程進行精細控制時,我們可以實現類型為 `JsonDeserializer<Map>>` 的自定義解器。

為了查看一個例子,假設我們的 JSON 中鍵為員工姓名,值為他們的入職日期。此外,假設日期的格式為 `yyyy/MM/dd>`,這與 `Gson>` 的標準格式不同。

我們可以配置 Gson 以不同的方式解析我們的 map,然後通過實現一個 `JsonDeserializer>`:

public class StringDateMapDeserializer implements JsonDeserializer<Map<String, Date>> {

    private SimpleDateFormat format = new SimpleDateFormat("yyyy/MM/dd");

    @Override
    public Map<String, Date> deserialize(JsonElement elem,
          Type type,
          JsonDeserializationContext jsonDeserializationContext) {
        return elem.getAsJsonObject()
          .entrySet()
          .stream()
          .filter(e -> e.getValue().isJsonPrimitive())
          .filter(e -> e.getValue().getAsJsonPrimitive().isString())
          .collect(
            Collectors.toMap(
              Map.Entry::getKey,
              e -> formatDate(e.getValue())));
    }

    private Date formatDate(Object value) {
        try {
            return format(value.getAsString());
        } catch (ParseException ex) {
            throw new JsonParseException(ex);
        }
    }
}

現在,我們需要在 GsonBuilder 中註冊它,針對目標類型 Map<String, Date>,並構建一個自定義的 Gson 對象。

當我們調用這個 Gson 對象的 fromJson API 時,解析器會調用自定義的脱敏器並返回所需的 Map 實例:

String jsonString = "{'Bob': '2017-06-01', 'Jennie':'2015-01-03'}";
Type type = new TypeToken<Map<String, Date>>(){}.getType();
Gson gson = new GsonBuilder()
  .registerTypeAdapter(type, new StringDateMapDeserializer())
  .create();
Map<String, Date> empJoiningDateMap = gson.fromJson(jsonString, type);
Assert.assertEquals(2, empJoiningDateMap.size());
Assert.assertEquals(Date.class, empJoiningDateMap.get("Bob").getClass());

這種策略在我們的地圖可能包含異構值的情況下也很有用,並且我們對可能存在的值類型數量有大致的瞭解。

要了解有關 Gson 中自定義反序列化的更多信息,請查看《Gson 反序列化食譜》。

5. 結論

在本文中,我們學習了多種構建從 JSON 格式字符串中創建地圖的方法。我們還討論了這些變體的正確使用場景。

user avatar
0 位用戶收藏了這個故事!
收藏

發佈 評論

Some HTML is okay.