记一次 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 ...
随机推荐
- PC端实现浏览器点击分享到QQ好友,空间,微信,微博等
网上现在比较流行的是JIaThis,但是测试的时候,不能分享给QQ好友,一直卡在输入验证码,以下代码亲测有效,可直接使用 <%@ page language="java" c ...
- VS2019配置MKL教程(Windows)
下载链接:https://software.intel.com/en-us/mkl 1.文件下载 官网注册后,选择MKL下载下来,安装到指定目录就行,不在多说. 2.配置文件 首先创建一个Window ...
- JavaScript基础8——弹窗案例
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title> ...
- JavaScript ES6 Promise对象
说明 Node.js中,以异步(Async)回调著称,使用了异步,提高了程序的执行效率,但是,代码可读性较差的. 假如有几个异步操作,后一个操作需要前一个操作的执行完毕之后返回的数据才能执行下去,如果 ...
- STM32之红外遥控信号自学习实现
一.序言 很早前就想实现这个红外遥控自学习的这个实验,用于来自己控制房子里如空调等红外遥控设备的自动化,NEC的标准到具体的产品上可能就被厂家定义为不一样了,所以自学习就应该是接收到什么就发送什么,不 ...
- This page includes a password or credit card input in a non-secure context. A warning has been added
此页面包含非安全上下文中的密码或信用卡输入.URL栏中添加了一个警告.有关更多信息,请参阅https://goo.gl/zmWq3m. 因为你的页面里面有input type是password,谷歌浏 ...
- python3-filter
Python内建的filter()函数用于过滤序列. 和map()类似,filter()也接收一个函数和一个序列.和map()不同的是,filter()把传入的函数依次作用于每个元素,然后根据返回值是 ...
- GPS通讯 数据包解析
全球时区的划分: 每个时区跨15°经度.以0°经线为界向东向西各划出7.5°经度,作为0时区.即0时区的经度范围是7.5°W——7.5°E.从7.5°E与7.5°W分别向东.向西每15°经度划分为一个 ...
- 【leetcode】1079. Letter Tile Possibilities
题目如下: You have a set of tiles, where each tile has one letter tiles[i]printed on it. Return the num ...
- 【leetcode】1047. Remove All Adjacent Duplicates In String
题目如下: Given a string S of lowercase letters, a duplicate removal consists of choosing two adjacent a ...