將值正確類型地序列化為 Map

Jackson,JSON
Remote
1
06:04 PM · Nov 30 ,2025

1. 簡介

反序列化是指將數據從一種格式,如 JSON、XML 或字節流,轉換回 Java 對象的過程。當我們通過反序列化到 Map<String, Object> 時,我們希望每個 map 中的值都具有正確的 Java 類型——不僅僅是字符串,還包括實際的整數、布爾值、數組和嵌套對象。

在本教程中,我們將學習如何正確地反序列化數據,同時保留每個字段的原始數據類型,使用多種不同的方法。

2. 使用 Jackson 庫

Jackson 是 Java 中最廣泛使用的 JSON 處理庫。 它提供快速、可靠的解復映射,並具有卓越的類型保留功能。

要使用 Jackson,我們首先需要在我們的 pom.xml 文件中添加依賴項:


<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>
    <version>2.19.2</version>
</dependency>

以下是如何使用 Jackson 的示例:

public class JacksonDeserializer {
    private final ObjectMapper objectMapper;
    
    public JacksonDeserializer() {
        this.objectMapper = new ObjectMapper();
    }
    
    public Map<String, Object> deserializeToMapUsingJackson(String jsonString) {
        try {
            TypeReference<Map<String, Object>> typeRef = new TypeReference<Map<String, Object>>() {};
            Map<String, Object> result = objectMapper.readValue(jsonString, typeRef);
            
            return result;
        } catch (Exception e) {
            throw new RuntimeException("Failed to deserialize JSON: " + e.getMessage(), e);
        }
    }
}

在此示例中,我們首先創建一個 ObjectMapper 對象來處理 JSON 處理。 然後,我們使用 TypeReference<Map<String, Object>> 來告訴 Jackson 我們想要將 JSON 解復映射到具有字符串鍵和不同類型值的映射中。

讓我們使用一個示例 JSON 進行測試:

String json = """
    {
        "name": "John",
        "age": 30,
        "isActive": true,
        "salary": 50000.75,
        "hobbies": ["reading", "coding"],
        "address": {
            "street": "123 Main St",
            "city": "New York"
        }
    }
    """;

Map<String, Object> result = deserializeToMapUsingJackson(json);

assertEquals("John", result.get("name"));
assertEquals(30, result.get("age"));
assertEquals(true, result.get("isActive"));
assertEquals(50000.75, result.get("salary"));
assertTrue(result.get("hobbies") instanceof ArrayList);

此測試確認 JSON 中的每個字段已成功解復映射到正確的 Java 類型 — String 用於 nameInteger 用於 ageBoolean 用於 isActiveDouble 用於 salary,以及 ArrayList 用於 hobbies

Jackson 的主要優勢在於它非常快速、可靠,並且具有處理不同類型 JSON 的卓越支持。

3. 使用 Gson 庫

Gson 是另一個流行的用於 Java 的 JSON 庫,由 Google 創建。它輕量級、易於使用,並且非常適合簡單的序列化和反序列化任務。

要使用 Gson,我們首先需要在我們的 pom.xml 文件中添加依賴項:


<dependency>
    <groupId>com.google.code.gson</groupId>
    <artifactId>gson</artifactId>
    <version>2.12.1</version>
</dependency>

這是一個使用 Gson 進行反序列化的示例:


public class GsonDeserializer {
    private final Gson gson;
    
    public GsonDeserializer() {
        this.gson = new Gson();
    }
    
    public Map<String, Object> deserializeToMapUsingGson(String jsonString) {
        try {
            Type type = new TypeToken<Map<String, Object>>() {}.getType();
            Map<String, Object> result = gson.fromJson(jsonString, type);
            return result;
        } catch (Exception e) {
            throw new RuntimeException("Failed to deserialize JSON: " + e.getMessage(), e);
        }
    }
}

首先,我們初始化一個 Gson 實例來處理 JSON 解析。 使用 TypeToken<Map<String, Object>>,我們告訴 Gson 將 JSON 反序列化為鍵為字符串,值為任何類型的映射。

讓我們用一個示例 JSON 進行測試:


Map<String, Object> result = deserializer.deserializeToMapUsingGson(json);

assertEquals("John", result.get("name"));
assertEquals(30.0, result.get("age"));
assertEquals(true, result.get("isActive"));
assertEquals(50000.75, result.get("salary"));
assertTrue(result.get("hobbies") instanceof ArrayList);

這個測試表明 Gson 成功地將 JSON 反序列化為 Map<String, Object>

但是,與 Jackson 不同,Gson 默認情況下將所有數字視為 Double,因此 agesalary 都被反序列化為 Double 這在我們需要嚴格的類型處理時需要注意。

Gson 的主要優勢是它非常簡單且輕量級,因此對於小型項目來説很容易設置。 缺點是與 Jackson 相比,類型保留性較弱,尤其是在處理數字時。

4. 使用 org.json 庫

org.json 庫是一個輕量級且簡單的工具,用於在 Java 中處理 JSON。它易於使用,並且適用於小規模或簡單的 JSON 解析任務。

要使用 org.json,我們可以添加 Maven 依賴:

<dependency>
    <groupId>org.json</groupId>
    <artifactId>json</artifactId>
    <version>20250107</version>
</dependency>

使用 org.json,我們可以將 JSON 解析為映射如下:

public class OrgJsonDeserializer {
    public Map<String, Object> deserializeToMapUsingOrgJson(String jsonString) {
        try {
            JSONObject jsonObject = new JSONObject(jsonString);
            Map<String, Object> result = new HashMap<>();

            for (String key : jsonObject.keySet()) {
                Object value = jsonObject.get(key);
                if (value instanceof JSONArray) {
                    value = ((JSONArray) value).toList();
                } else if (value instanceof JSONObject) {
                    value = ((JSONObject) value).toMap();
                }
                result.put(key, value);
            }

            return result;
        } catch (Exception e) {
            throw new RuntimeException("Failed to deserialize JSON: " + e.getMessage(), e);
        }
    }
}

在示例中,我們創建一個 JSONObject 來解析 JSON 字符串。然後我們遍歷其鍵,將每個值轉換為。 如果值是 JSONArray,我們將它轉換為 List 以便在 Java 中更輕鬆地處理。 這為我們提供了一個 Map<String, Object>,其中每個值可以是基本類型或列表。

讓我們使用示例 JSON 測試實現:

Map<String, Object> result = deserializer.deserializeToMapUsingOrgJson(json);

assertEquals("John", result.get("name"));
assertEquals(30, result.get("age"));
assertEquals(true, result.get("isActive"));
assertEquals(BigDecimal.valueOf(50000.75), result.get("salary"));
assertTrue(result.get("hobbies") instanceof List);
assertTrue(result.get("address") instanceof Map);

此測試表明 org.json 成功地將 JSON 轉換為 Map<String, Object>與 Gson 相比,數值值被保留為 Integer,並使用 BigDecimal 來處理小數以保持精度。 這可以使類型處理對於混合數字來説更簡單一些。

但是,org.json 的主要侷限性是它不像 Jackson 或 Gson 那樣自動處理複雜的類型映射或嵌套對象。

對於小型項目或快速解析任務,它是一個堅實且輕量級的選擇。

5. Using JSON-P (Java JSON Processing API)

JSON-P (Java API for JSON Processing) 是一種標準化的 Java API,用於 JSON 處理。它允許手動解析 JSON,並對類型轉換具有完全控制權,這使得它非常精確,但略顯冗長。

要使用 JSON-P,我們需要為 API 和一個 實現 添加依賴項到我們的 pom.xml 文件中:


    
        jakarta.json
        jakarta.json-api
        2.1.3
    
    
        org.eclipse.parsson
        parsson
        1.1.5
    

使用 JSON-P,我們可以將 JSON 解析為 map,同時顯式處理每個值的類型:


public class JsonPDeserializer {
    public Map<String, Object> deserializeToMapUsingJSONP(String jsonString) {
        try (JsonReader reader = Json.createReader(new StringReader(jsonString))) {
            JsonObject jsonObject = reader.readObject();
            return convertJsonToMap(jsonObject);
        } catch (Exception e) {
            throw new RuntimeException("JSON-P parsing failed: " + e.getMessage(), e);
        }
    }

    private Map<String, Object> convertJsonToMap(JsonObject jsonObject) {
        Map<String, Object> result = new HashMap<>();

        for (Map.Entry<String, JsonValue> entry : jsonObject.entrySet()) {
            String key = entry.getKey();
            JsonValue value = entry.getValue();
            result.put(key, convertJsonValue(value));
        }

        return result;
    }

    private Object convertJsonValue(JsonValue jsonValue) {
        switch (jsonValue.getValueType()) {
            case STRING:
                return ((JsonString) jsonValue).getString();
            case NUMBER:
                jakarta.json.JsonNumber num = (JsonNumber) jsonValue;
                return num.isIntegral() ? num.longValue() : num.doubleValue();
            case TRUE:
                return true;
            case FALSE:
                return false;
            case NULL:
                return null;
            case ARRAY:
                return convertJsonArray((JsonArray) jsonValue);
            case OBJECT:
                return convertJsonToMap((JsonObject) jsonValue);
            default:
                return jsonValue.toString();
        }
    }

    private List<Object> convertJsonArray(JsonArray jsonArray) {
        List<Object> list = new ArrayList<>();
        for (JsonValue value : jsonArray) {
            list.add(convertJsonValue(value));
        }
        return list;
    }
}

在示例中,我們使用一個 JsonReader 來解析 JSON 字符串為 JsonObject。然後我們手動轉換每個值,使用 convertJsonValue(),該方法處理字符串、數字、布爾值、數組、嵌套對象和 null 值。

數組 被轉換為 List<Object> 以便在 Java 中更輕鬆地處理。這種方法提供了對每個 JSON 值如何轉換為相應的 Java 類型完全的控制。

我們可以使用以下示例進行驗證:


Map<String, Object> result = deserializeToMapUsingJSONP(json);

assertEquals("John", result.get("name"));
assertEquals(30.0, result.get("age"));
assertEquals(true, result.get("isActive"));
assertEquals(50000.75, result.get("salary"));
assertTrue(result.get("hobbies") instanceof List);
assertTrue(result.get("address") instanceof Map);

JSON-P 仔細解析數字;整數和小數轉換為 Double,以確保精確的類型處理。

使用 JSON-P 的主要優勢在於它提供了對類型轉換的精確控制,這使得它在需要精確處理數字、布爾值和嵌套結構時非常理想。權衡是代碼更冗長,並且我們必須手動處理所有 JSON 類型。

6. 總結

以下是比較 Jackson、Gson、org.json 和 JSON-P 的總結表:

庫 (庫) 依賴 (依賴) 類型處理 (類型處理) 使用場景 (使用場景)
Jackson 是 (是) 極佳的類型保留 (Integer, Long, Double, Boolean, List, 嵌套對象 (嵌套對象)) 生產應用 (應用), 複雜 JSON 結構 (結構), 性能關鍵項目 (項目)
Gson 是 (是) 數字 (數字) 默認 (默認) 為 Double; 處理 Boolean, String, List, 和 嵌套對象 (嵌套對象) 簡單項目 (項目), 輕量級 JSON 解析 (解析), 快速設置 (設置)
org.json 是 (是) (或有時包含在其中) Integer 和 Double 保留 (保留), Boolean, String, JSONArray 轉換為 List 小型項目 (項目), 簡單 JSON 解析 (解析), 最小依賴 (依賴)
JSON-P 否 (否), Java 標準的一部分 (的一部分) Numbers 默認 (默認) 為 Double; 處理 Boolean, String, List, 嵌套對象 (嵌套對象), 和 nulls 顯式 (顯式) 當需要精確的類型控制 (控制) 時, 需要嚴格的解析和標準 Java 項目 (項目)。

7. 結論

在本文中,我們探討了多種將 JSON 數據反序列化為 Map<String, Object> 的方法,同時保持正確的數據類型。 Jackson 為複雜的 JSON 提供最全面的解決方案,而 Gson、org.json 和 JSON-P 則根據我們的項目要求提供更輕量級或更精細的替代方案。

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

發佈 評論

Some HTML is okay.