1、概览 {#1概览}
本文将带你了解如何解决 Jackson 异常:JsonMappingException: Can not deserialize instance of java.util.HashMap out of START_ARRAY token。
2、理解异常 {#2理解异常}
简而言之,Jackson 在反序列化 JSON 字符串时抛出 JsonMappingException 来指示映射错误。而,"Can not deserialize instance of java.util.HashMap out of START_ARRAY token" 异常消息表示预期的数据结构与实际的 JSON 字符串不匹配。
这里出现不匹配是因为 Jackson 期望的是 List 而不是 HashMap。反序列化过程不知道如何将指定的 JSON 数组转换为 HashMap。因此出现异常。
3、示例 {#3示例}
来看一个会导致 Jackson 出现 JsonMappingException 异常的例子。
为了简单起见,假设我们有一个 JSON 数组,其中每个元素都代表一个由名(firstName)和姓(lastName)定义的人:
[
    {
        "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、解决办法 {#4解决办法}
默认情况下,Jackson 希望在反序列化 JSON 数组时使用 List。因此,最直接的解决方案是使用 List<Map> 而不是单个 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<Map<String, String>>。
或者,我们可以创建一个自定义类来表示每个 JSON 元素。
定义 Person 类:
public class Person {
    private String firstName;
    private String lastName;
//忽略构造函数和 Getter / Setter 方法
}
这里的基本思想是使用 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 返回 Person 对象的 List,而不是 Map<String, String> 的 List。
5、总结 {#5总结}
本文介绍了 Jackson 抛出 "JsonMappingException: Can not deserialize instance of java.util.HashMap out of START_ARRAY token" 异常的主要原因,以及解决办法。
Ref:https://www.baeldung.com/java-fix-the-jsonmappingexception-can-not-deserialize-instance-of-java-util-hashmap-out-of-start_array-token
 51工具盒子
51工具盒子 
                 
                             
                         
                         
                         
                         
                         
                        