知識庫 / JSON / Jackson RSS 訂閱

修復JsonMappingException:無法從START_ARRAY標記處反序列化java.util.HashMap實例

Jackson
HongKong
11
09:41 PM · Dec 05 ,2025

1. 概述

本教程將介紹如何解決 Jackson 異常 `JsonMappingException: Can not deserialize instance of java.util.HashMap out of START_ARRAY token》。

首先,我們將闡明該異常的根本原因。然後,我們將通過一個實際示例演示如何重現該異常,最後,我們將提供解決方案。

2. 理解異常

Jackson 通過拋出 <em>JsonMappingException</em> 來指示在反序列化 JSON 字符串時發生的映射錯誤。 此外,消息 <em>“Can not deserialize instance of java.util.HashMap out of START_ARRAY token”</em>&nbsp; 表明預期的數據結構與實際的 JSON 字符串之間存在不匹配。

這裏不匹配的原因在於 Jackson 期望一個 <em>List</em> 而不是一個 <em>HashMap</em>。 反序列化過程無法將指定的 JSON 數組轉換為 <em>HashMap</em>。 因此,拋出了異常。

3. 實際示例

現在我們瞭解了導致 Jackson 失敗的原因(即 JsonMappingException),讓我們通過一個實際示例來演示如何重現它。

為了簡化問題,假設我們有一個 JSON 數組,其中每個元素代表一個人,由名字和姓氏定義:

[
    {
        "firstName":"Abderrahim",
    	"lastName":"Azhrioun"
    }, 
    {
    	"firstName":"Nicole",
        "lastName":"Smith"
    }
]

現在,嘗試直接將 JSON 數組反序列化為 Map 將會導致 JsonMappingException

@Test
public void givenJsonArray_whenDeserializingToMap_thenThrowException() {
    final String json = "[{\"firstName\":\"Abderrahim\",\"lastName\":\"Azhrioun\"}, {\"firstName\":\"Nicole\",\"lastName\":\"Smith\"}]";
    final ObjectMapper mapper = new ObjectMapper();

    Exception exception = assertThrows(JsonMappingException.class, () -> mapper.readValue(json, HashMap.class));

    assertTrue(exception.getMessage()
      .contains(
          "Cannot deserialize value of type `java.util.HashMap<java.lang.Object,java.lang.Object>` from Array value (token `JsonToken.START_ARRAY`)"));
}

如我們所見,Jackson 由於遇到 ObjectMapper 不知道如何直接將給定的 JSON 數組反序列化為 HashMap

4. 解決方案

默認情況下,Jackson 期望在反序列化 JSON 數組時得到一個 List。因此,最直接的解決方案是使用一個包含 MapList,而不是一個單獨的 Map

讓我們來看一個示例:

@Test
public void givenJsonArray_whenDeserializingToListOfMap_thenConvert() throws JsonProcessingException {
    final List<Map<String, String>> expectedListOfMaps = Arrays.asList(Map.of("firstName", "Abderrahim", "lastName", "Azhrioun"),
        Map.of("firstName", "Nicole", "lastName", "Smith"));
    final String json = "[{\"firstName\":\"Abderrahim\",\"lastName\":\"Azhrioun\"}, {\"firstName\":\"Nicole\",\"lastName\":\"Smith\"}]";
    final ObjectMapper mapper = new ObjectMapper();

    List<Map<String, String>> personList = mapper.readValue(json, new TypeReference<>() {});

    assertThat(expectedListOfMaps).isEqualTo(personList);
}

如上所示,我們使用 TypeReference 指示 Jackson 將 JSON 數組反序列化為包含 Map<String, String>List

或者,我們可以創建一個自定義類來表示每個 JSON 元素。 例如,讓我們考慮 Person 類:

public class Person {
    private String firstName;
    private String lastName;

    // default constructor, full parameterized constructor, getters and setters
}

基本思路是使用 Person 類而不是 Map<String, String>這樣,每個 JSON 數組的元素都會映射到一個 Person 對象。 讓我們用另一個測試用例來確認這一點:

@Test
public void givenJsonArray_whenDeserializingToListOfCustomObjects_thenConvert() throws JsonProcessingException {
    final List<Person> expectedPersonList = Arrays.asList(new Person("Abderrahim", "Azhrioun"), new Person("Nicole", "Smith"));
    final String json = "[{\"firstName\":\"Abderrahim\",\"lastName\":\"Azhrioun\"}, {\"firstName\":\"Nicole\",\"lastName\":\"Smith\"}]";
    final ObjectMapper mapper = new ObjectMapper();

    List<Person> personList = mapper.readValue(json, new TypeReference<>() {});

    assertThat(expectedPersonList).usingRecursiveComparison()
      .isEqualTo(personList);
}

在這裏,我們告訴 Jackson 返回一個 List 包含 Person 對象,而不是一個 List 包含 Map<String, String> 對象。

5. 結論

在本文中,我們解釋了 Jackson 異常 <em >JsonMappingException: Can not deserialize instance of java.util.HashMap out of START_ARRAY token</em> 的主要原因。 在過程中,我們演示瞭如何重現該異常以及如何解決它。

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

發佈 評論

Some HTML is okay.