1、描述

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

2、问题复现

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

     @Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
private static class JsonResult<T> {
private String message;
private T result; // 问题出现在这里
} @Builder
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
private static class Container {
private String key;
private String value;
}

使用如下的测试的用例

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

将会得到错误: 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 泛型

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

 private static class ContainerJsonRsult extends JsonResult<Container>{}

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

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

4.2.1.2 Object

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

     @Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
private static class ContainerJsonResult extends JsonResult {
private Container result;
}

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

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

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

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

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

  或者

         JavaType type = mapper.getTypeFactory().constructType(Container.class);
Container container = mapper.convertValue(parsedResult.result, type);

记一次 Json 对象转换为 Java 对象的问题的更多相关文章

  1. Json字符串转换为java对象的各种实现方法【json_lib框架、Gson、org.json】

    原创作品,允许转载,转载时请务必以超链接形式标明文章 原始出处 .作者信息和本声明.否则将追究法律责任.http://mengzhengbin520.blog.51cto.com/7590564/12 ...

  2. JSON字符串与java对象的转换

    所需的jar包: 1.commons-lang.jar 2.commons-beanutils.jar 3.commons-collections.jar 4.commons-logging.jar ...

  3. JSON 字符串 与 java 对象的转换

    jsonLib 经典文章:http://json-lib.sourceforge.net/xref-test/net/sf/json/TestJSONObject.html // 引入相应的包 //j ...

  4. Json对象与Json字符串的转化、JSON字符串与Java对象的转换

    一.Json对象与Json字符串的转化 1.jQuery插件支持的转换方式: $.parseJSON( jsonstr ); //jQuery.parseJSON(jsonstr),可以将json字符 ...

  5. Json对象与Json字符串的转化、JSON字符串与Java对象的转换(转)

    一.Json对象与Json字符串的转化 1.jQuery插件支持的转换方式: $.parseJSON( jsonstr ); //jQuery.parseJSON(jsonstr),可以将json字符 ...

  6. json字符串与java对象的相互转换(jackson)

    1.java对象转换为json字符串 package com.chichung.json; import com.fasterxml.jackson.core.JsonProcessingExcept ...

  7. Json——使用Json jar包实现Json字符串与Java对象或集合之间的互相转换

    总结一下利用Json相关jar包实现Java对象和集合与Json字符串之间的互相转换: 1.创建的User类: package com.ghj.packageofdomain; public clas ...

  8. json字符串,json对象,java对象互相转换

    1.把JSON字符串转换为JAVA 对象 JSONObject jsonobject = JSONObject.fromObject(jsonStr); User user= (User)JSONOb ...

  9. JSon_零基础_007_将JSon格式的"数组"字符串转换为Java对象"数组"

    将JSon格式的"数组"字符串转换为Java对象"数组". 应用此技术从一个json对象字符串格式中得到一个java对应的对象. JSONObject是一个“n ...

随机推荐

  1. 分布式唯一ID生成器

    在应用程序中,经常需要全局唯一的ID作为数据库主键.如何生成全局唯一ID? 首先,需要确定全局唯一ID是整型还是字符串?如果是字符串,那么现有的UUID就完全满足需求,不需要额外的工作.缺点是字符串作 ...

  2. 行人重识别(ReID) ——基于MGN-pytorch进行可视化展示

    下载MGN-pytorch:https://github.com/seathiefwang/MGN-pytorch 下载Market1501数据集:http://www.liangzheng.org/ ...

  3. 快速禁止Chrome浏览器缓存

    在前端的开发中,最麻烦的莫过于浏览器的缓存,经常需要清理缓存文件,导致开发效率较低. 但Chrome可以一键禁止浏览器缓存,并且在后续的操作中,无论相同的资源请求多少次,都不会缓存到本地,一起来体验下 ...

  4. 1144. The Missing Number (20)

    Given N integers, you are supposed to find the smallest positive integer that is NOT in the given li ...

  5. Message相关函数对比

      SendMessage PostMessage  过程类型 同步过程:等待其他程序处理消息完了之后才返回,继续执行 异步过程:只把消息放入队列,不管其他程序是否处理都返回,然后继续执行 返回值 表 ...

  6. hadoop中的一些术语介绍

    1.MR作业是客户端执行的一个工作单元:包括输入数据,MR的程序和配置信息. Hadoop将作业分成若干个任务task来执行,分为两种任务:map和reduce任务.这些任务运行在集群的节点上,并通过 ...

  7. MongoDB Compass管理工具下载、安装和使用

    内容来自:https://jingyan.baidu.com/article/925f8cb884f6f8c0dce0565a.html ,https://blog.csdn.net/bg101775 ...

  8. Flsak中的socket是基于werkzeug实现的。

    from werkzeug.serving import run_simple from werkzeug.wrappers import Request,Respinse @Request.appl ...

  9. Vue----项目增加百度统计

    到百度统计->注册账号->新增网址->获取代码 在Vue单页面开发中接入百度统计代码时,如果直接按照官网的走会出现错误,就是_hmt找不到,这是因为在一个js文件里声明的变量在另一个 ...

  10. APP稳定性测试-monkey执行

    Monkey命令行可用的全部选项 *示例 : adb shell monkey -p cn.lejiayuan.alpha --pct-touch 30 --pct-motion 15 --pct-t ...