知識庫 / JSON / Jackson RSS 訂閱

將對象反序列化為具有每個值的正確類型的 Map

Jackson,JSON
HongKong
5
09:40 PM · Dec 05 ,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 是 Google 創建的另一個流行的 Java JSON 庫。它輕量級、易於使用,並且非常適合簡單的序列化和反序列化任務。

要使用 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. 使用 JSON-P (Java JSON 處理 API)

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

要使用 JSON-P,我們需要在我們的 pom.xml 文件中添加對 API 和實現的依賴:

<dependency>
    <groupId>jakarta.json</groupId> 
    <artifactId>jakarta.json-api</artifactId> 
    <version>2.1.3</version> 
</dependency>
<dependency>
    <groupId>org.eclipse.parsson</groupId>
    <artifactId>parsson</artifactId>
    <version>1.1.5</version>
</dependency>

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

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 類型。

我們可以使用示例 JSON 驗證實現:

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 標準的一部分 數字默認轉換為 Double; 處理 Boolean, String, List, 嵌套對象,以及明確的 null 當需要精確的類型控制時,需要嚴格的解析和標準 Java 項目。

7. 結論

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

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

發佈 評論

Some HTML is okay.