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

Jackson
Remote
1
06:37 PM · Nov 30 ,2025

1. 概述

在本簡短教程中,我們將探討如何解決 Jackson 異常 JsonMappingException: Can not deserialize instance of java.util.HashMap out of START_ARRAY token

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

2. 理解異常

簡而言之,Jackson 在反序列化 JSON 字符串時,會拋出 JsonMappingException 以指示映射錯誤。 此外,消息 “Can not deserialize instance of java.util.HashMap out of START_ARRAY token”  表明預期數據結構與實際 JSON 字符串之間存在不匹配

此處不匹配的原因是 Jackson 期望一個 List 而不是一個 HashMap。 反序列化過程不知道如何將指定的 JSON 數組轉換為 HashMap。 因此,拋出了異常。

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 由於 “Cannot deserialize value of type HashMap from Array value (token `JsonToken.START_ARRAY`)” 而失敗,因為 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 數組反序列化為 List,該 List 包含 Map<String, String> 對象。

或者,我們可以創建一個自定義類來表示每個 JSON 元素

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,該 List 包含 Person 對象,而不是 List,該 List 包含 Map<String, String> 對象。

5. 結論

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

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

發佈 評論

Some HTML is okay.