记一次 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 ...
随机推荐
- CentOS7搭建Docker镜像实战
开发十年,就只剩下这套架构体系了! >>> 一.搭建环境 使用的是VMWare 12虚拟机安装的CentOS7 安装成功后修改ip: 1. ip addr查看相关信息: 2. 修 ...
- Opencv中KNN背景分割器
背景分割器BackgroundSubtractor是专门用来视频分析的,会对视频中的每一帧进行"学习",比较,计算阴影,排除检测图像的阴影区域,按照时间推移的方法提高运动分析的结果 ...
- golang中读取文件
读文件 方式1 #利用ioutil.ReadFile 直接从文件读取到[]byte中# file, err := ioutil.ReadFile("file/test.txt") ...
- Kubernetes部署DNS
前言 阅读地址 http://thoreauz.com/2017/04/16/docker/Kubernetes%E9%83%A8%E7%BD%B2DNS%E5%92%8CDashboard/ Kub ...
- luogu P3411 序列变换
链接 P3411 序列变换 如果要最小化答案,那么就最大化不移动的数. 那么不移动的子序列一定是最后答案的一段连续区间,而移动的数我们是一定有办法把他们还原的. 设\(f_{i}\)表示\(i\)点的 ...
- 快速开发框架下载地址(github)
eladmin:https://github.com/elunez/eladmin bootDo:https://www.oschina.net/p/bootdo
- Python---基础---循环,函数
2019-05-21 ----------------------------------- # 打印出一个矩形# 控制行for i in range(1, 5): #控制列 for j ...
- RMQ Fanout
原创转载请注明出处:https://www.cnblogs.com/agilestyle/p/11795256.html RMQ Fanout Project Directory Maven Depe ...
- handy源码阅读(二):EventsImp类
EventsImp用于完成事件的处理. class EventsImp { EventBase* base_; PollerBase* poller_; std::atomic<bool> ...
- php current()函数 语法
php current()函数 语法 作用:返回数组中的当前元素的值.直线电机工作原理 语法:current(array) 参数: 参数 描述 array 必需.规定要使用的数组. 说明:返回数组中的 ...