记一次 Json 对象转换为 Java 对象的问题
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 对象的问题的更多相关文章
- Json字符串转换为java对象的各种实现方法【json_lib框架、Gson、org.json】
原创作品,允许转载,转载时请务必以超链接形式标明文章 原始出处 .作者信息和本声明.否则将追究法律责任.http://mengzhengbin520.blog.51cto.com/7590564/12 ...
- JSON字符串与java对象的转换
所需的jar包: 1.commons-lang.jar 2.commons-beanutils.jar 3.commons-collections.jar 4.commons-logging.jar ...
- JSON 字符串 与 java 对象的转换
jsonLib 经典文章:http://json-lib.sourceforge.net/xref-test/net/sf/json/TestJSONObject.html // 引入相应的包 //j ...
- Json对象与Json字符串的转化、JSON字符串与Java对象的转换
一.Json对象与Json字符串的转化 1.jQuery插件支持的转换方式: $.parseJSON( jsonstr ); //jQuery.parseJSON(jsonstr),可以将json字符 ...
- Json对象与Json字符串的转化、JSON字符串与Java对象的转换(转)
一.Json对象与Json字符串的转化 1.jQuery插件支持的转换方式: $.parseJSON( jsonstr ); //jQuery.parseJSON(jsonstr),可以将json字符 ...
- json字符串与java对象的相互转换(jackson)
1.java对象转换为json字符串 package com.chichung.json; import com.fasterxml.jackson.core.JsonProcessingExcept ...
- Json——使用Json jar包实现Json字符串与Java对象或集合之间的互相转换
总结一下利用Json相关jar包实现Java对象和集合与Json字符串之间的互相转换: 1.创建的User类: package com.ghj.packageofdomain; public clas ...
- json字符串,json对象,java对象互相转换
1.把JSON字符串转换为JAVA 对象 JSONObject jsonobject = JSONObject.fromObject(jsonStr); User user= (User)JSONOb ...
- JSon_零基础_007_将JSon格式的"数组"字符串转换为Java对象"数组"
将JSon格式的"数组"字符串转换为Java对象"数组". 应用此技术从一个json对象字符串格式中得到一个java对应的对象. JSONObject是一个“n ...
随机推荐
- 分布式唯一ID生成器
在应用程序中,经常需要全局唯一的ID作为数据库主键.如何生成全局唯一ID? 首先,需要确定全局唯一ID是整型还是字符串?如果是字符串,那么现有的UUID就完全满足需求,不需要额外的工作.缺点是字符串作 ...
- 行人重识别(ReID) ——基于MGN-pytorch进行可视化展示
下载MGN-pytorch:https://github.com/seathiefwang/MGN-pytorch 下载Market1501数据集:http://www.liangzheng.org/ ...
- 快速禁止Chrome浏览器缓存
在前端的开发中,最麻烦的莫过于浏览器的缓存,经常需要清理缓存文件,导致开发效率较低. 但Chrome可以一键禁止浏览器缓存,并且在后续的操作中,无论相同的资源请求多少次,都不会缓存到本地,一起来体验下 ...
- 1144. The Missing Number (20)
Given N integers, you are supposed to find the smallest positive integer that is NOT in the given li ...
- Message相关函数对比
SendMessage PostMessage 过程类型 同步过程:等待其他程序处理消息完了之后才返回,继续执行 异步过程:只把消息放入队列,不管其他程序是否处理都返回,然后继续执行 返回值 表 ...
- hadoop中的一些术语介绍
1.MR作业是客户端执行的一个工作单元:包括输入数据,MR的程序和配置信息. Hadoop将作业分成若干个任务task来执行,分为两种任务:map和reduce任务.这些任务运行在集群的节点上,并通过 ...
- MongoDB Compass管理工具下载、安装和使用
内容来自:https://jingyan.baidu.com/article/925f8cb884f6f8c0dce0565a.html ,https://blog.csdn.net/bg101775 ...
- Flsak中的socket是基于werkzeug实现的。
from werkzeug.serving import run_simple from werkzeug.wrappers import Request,Respinse @Request.appl ...
- Vue----项目增加百度统计
到百度统计->注册账号->新增网址->获取代码 在Vue单页面开发中接入百度统计代码时,如果直接按照官网的走会出现错误,就是_hmt找不到,这是因为在一个js文件里声明的变量在另一个 ...
- APP稳定性测试-monkey执行
Monkey命令行可用的全部选项 *示例 : adb shell monkey -p cn.lejiayuan.alpha --pct-touch 30 --pct-motion 15 --pct-t ...