zoukankan      html  css  js  c++  java
  • 记一次 Json 对象转换为 Java 对象的问题

    1、描述

    最近在使用 Jackson 将 Json 串转换回 Java 对象的时候遇到了 ClassCastException 错误,特此记述。

    2、问题复现

    问题出现的节点在于属性节点的 JavaType 不明确,比如使用了泛型 和 Object,如下:

     1     @Getter
     2     @Setter
     3     @NoArgsConstructor
     4     @AllArgsConstructor
     5     private static class JsonResult<T> {
     6         private String message;
     7         private T result; // 问题出现在这里
     8     }
     9 
    10     @Builder
    11     @Getter
    12     @Setter
    13     @NoArgsConstructor
    14     @AllArgsConstructor
    15     private static class Container {
    16         private String key;
    17         private String value;
    18     }

    使用如下的测试的用例

     1     @Test
     2     void testWrite() throws JsonProcessingException {
     3         final ObjectMapper mapper = new ObjectMapper();
     4         mapper.setVisibility(PropertyAccessor.FIELD, JsonAutoDetect.Visibility.ANY);
     5         final JsonResult<Container> resultBefore = new JsonResult<>();
     6         resultBefore.setMessage("foo");
     7         final Container containerBefore = Container.builder().key("key").value("value").build();
     8         resultBefore.setResult(containerBefore);
     9         final String writtenString = mapper.writeValueAsString(resultBefore);
    10         //----------------read str as object
    11         final JsonResult parsedResult = mapper.readValue(writtenString, JsonResult.class);
    12         assert parsedResult != null; // 之后将在这里打断点
    13 
    14         final Container container = (Container) parsedResult.result;
    15         assertThat(container).as("not null").isNotNull().extracting(Container::getKey).as("key equal").isEqualTo(containerBefore.key);
    16         assertThat(container).extracting(Container::getValue).as("key equal").isEqualTo(containerBefore.value);
    17     }
    18 }

    将会得到错误: java.lang.ClassCastException: java.util.LinkedHashMap cannot be cast to Container

    3、问题解析

    让我们在测试中打上断点,看看经由 jackson 反序列化后的对象内容

      可以看到这时候 Container 类的内容在这里变成了 hashMap,其实各种原因不难理解,在序列化跟反序列化中,我们给 Jackson 传递的 Class 是 JsonResult,回到相应类的定义,会发现我们使用的是泛型,Jackson 并不知道 rsult 中实际存放的类型,对 Object 也是如此(Object 是所有非原始类型的祖先)

      在 ide 的提示里,我们也可以看到这时候 parsedResult 里边的 result 实际上是 Object 类型

    4、思路与解决方式

    4.1 思路

      从上边的分析来,看解决的思路很简单,我们需要告诉 Jackson  result 中存放的数据类型。方法有二

    4.2 解决方式

    4.2.1 改变反序列化时传递的 Class 参数

    4.2.1.1 泛型

      当对象有泛型参数时候,我们只要构建一个新类型,让它继承原本的类并指定泛型参数即可。在原本的代码中,我们加入。 

    1 private static class ContainerJsonRsult extends JsonResult<Container>{}

      并且改变相应的反序列化语句即可。

    final ContainerJsonRsult parsedResult = mapper.readValue(writtenString, ContainerJsonRsult.class);

    4.2.1.2 Object

      当对象的没有泛型签名时,我们需要构建一个新类型,让他继承原本的类,并让他拥有目标 Containner 类型的同名参数 result

    1     @Getter
    2     @Setter
    3     @NoArgsConstructor
    4     @AllArgsConstructor
    5     private static class ContainerJsonResult extends JsonResult {
    6         private Container result;
    7     }

      然后修改对应的反序列语句:

    1 final ContainerJsonResult parsedResult = mapper.readValue(writtenString, ContainerJsonResult.class);

    2、在反序列化中手动传递 result 对应的 Calss 类型

    对于存在泛型的类,推荐 4.2.1.1 的解决方式,当 rsult 中指向的是 Object 或者 T  类型时,都可以指定相应的 Class 类进行二次转换:

    1  Container container = mapper.convertValue(parsedResult.getResult(), Container.class);

      或者

    1         JavaType type = mapper.getTypeFactory().constructType(Container.class);
    2         Container container = mapper.convertValue(parsedResult.result, type);
  • 相关阅读:
    【转】 java中Class对象详解和类名.class, class.forName(), getClass()区别
    106. Construct Binary Tree from Inorder and Postorder Traversal
    105. Construct Binary Tree from Preorder and Inorder Traversal
    107. Binary Tree Level Order Traversal II
    109. Convert Sorted List to Binary Search Tree
    108. Convert Sorted Array to Binary Search Tree
    110. Balanced Binary Tree
    STL容器迭代器失效问题讨论
    113. Path Sum II
    112. Path Sum
  • 原文地址:https://www.cnblogs.com/siweipancc/p/json-cast-to-java-ClassCastException-java-util-LinkedHashMap-cannot-be-cast-to-Entity.html
Copyright © 2011-2022 走看看