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. sys模块与shutil模块

    #coding=utf-8 import sys ## sys.argv #从命令行获取参数 import shutil #文件.文件夹.压缩包.处理模块 f1 = open("test.t ...

  2. express快速入门

    1.简介: express是基于Node.js平台,快速开放极简的web开发框架,使用 各种http使用工具和中间件,创建强大API. 2.安装 npm install express -g 全局安装 ...

  3. linux下查看Apache的访问日志及ip

    linux下查看Apache的实时访问日志:tail -f  /etc/httpd/logs/access_log 查看有哪些ip访问过:cat access_log |awk '{print $1} ...

  4. Object of type 'ndarray' is not JSON serializable

    Object of type 'ndarray' is not JSON serializable import numpy as np import json arr=np.asarray([345 ...

  5. neovim初次安装使用

    github下载neovim代码 按readme中安装,中间可能 要安装一些库 将vim的配置关联到nvim,发现和vim是一样的 ln -s ~/.vim ~/.config/nvim ln -s ...

  6. centos7卸载YUM后重装过程 -bash: yum: command not found / -bash: yum: 未找到命令

    [root@localhost ~]# rpm -qa |grep yum yum-3.4.3-158.el7.centos.noarch yum-plugin-fastestmirror-1.1.3 ...

  7. service mesh学习规划

    istio go语言 谷歌开发 现有产品功能(每个功能具体支持哪些方式,优缺点) 服务注册发现 流量劫持 路由 负载均衡 熔断降级 流量控制(限流.流量分配) 重试机制 日志管理 支持的协议 监控(健 ...

  8. motd - 当日消息

    描述 (DESCRIPTION) 在 登录 系统 后, 执行 登录 shell 前, login(1) 显示 /etc/motd 中的 内容. "motd" 意思是 "m ...

  9. Linux--shell grep与正则表达式--04

    一.grep程序 Linux下有文本处理三剑客:grep.sed.awk grep:文本 行过滤工具 sed:文本 行编辑器(流编辑器) awk:报告生成器(做文本输出格式化) 1.grep grep ...

  10. DNS服务的安装

    DNS服务器原理及配置 域名讲解 www.baidu.com 完整的域名,通常.来进行分割三个部分:www是主机名,baidu是域名,com是类型 主机名 + 域名 + 类型 构成完整的域名 DNS服 ...