Feign在进行序列化时遇到泛型类型的擦除,导致反序列化时成了LinkedHashMap

news2025/1/18 3:27:40

Feign在进行序列化时遇到泛型类型的擦除,导致反序列化时成了LinkedHashMap

    • 故障背景
    • 问题分析
    • 修复方案
      • 修复方案一 避免使用泛型
      • 修复方案二 解析data泛型的时候处理

故障背景

假设我们有一个Feign接口

import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.cloud.openfeign.SpringQueryMap;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.PostMapping;

@FeignClient(name = "testJdkDateTimeRpcService", url = "${query-current-service-provider.prevBaseUrl}")
public interface TestJdkDateTimeRpcService {
    /**
     * 测试JDK Date 类型序列化和反序列化
     * @param testJdkDateTimeParam
     * @return
     */
    @PostMapping(value = "/rpc-service/testJdkDateTimeRpcService/fetchParamIncludeJdkDateTime.do",
            consumes = MediaType.ALL_VALUE,
            produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
    VueElementAdminResponse fetchParamIncludeJdkDateTime(@SpringQueryMap TestJdkDateTimeParam testJdkDateTimeParam);
}

其中这个接口响应结果对象中包含有泛型,比如Object,

@Data
public class VueElementAdminResponse implements Serializable {
    private static final long serialVersionUID = -3368531539063907497L;
    private Integer code;
    private String message;
    private Object data;
    private String trackId = SmartStringUtils.getSnowFlakeStrId();
}

还有一个业务对象

import lombok.Data;

import java.io.Serializable;

@Data
public class TestJdkDateTimeParam implements Serializable {
    private static final long serialVersionUID = -5346602757850243509L;
    private String id;
    private String testDate;
}

然后我们定义了一个Feign 调用接口

import org.springframework.web.bind.annotation.*;

@RequestMapping(value = "/rpc-service/testJdkDateTimeRpcService")
@RestController
public class TestJdkDateTimeRpcController {

    @PostMapping(value = "/fetchParamIncludeJdkDateTime.do")
    public VueElementAdminResponse fetchParamIncludeJdkDateTime(@ModelAttribute TestJdkDateTimeParam testJdkDateTimeParam){
        VueElementAdminResponse vueElementAdminResponse=new VueElementAdminResponse();
        vueElementAdminResponse.setCode(20000);
        vueElementAdminResponse.setMessage("/rpc-service/testJdkDateTimeRpcService/fetchParamIncludeJdkDateTime.do-测试Feign调用时JDK DateTime 序列化和反序列化");
        vueElementAdminResponse.setData(testJdkDateTimeParam);
        return vueElementAdminResponse;
    }
}

值得注意的是:
我们在VueElementAdminResponse 对象的data中赋值 一个TestJdkDateTimeParam对象

最后再定义一个本地调用的接口:

@Slf4j
@RequestMapping(value = "/test-service/testJdkDateTimeRpcService")
@RestController
public class TestJdkDateTimeWebController {

    private final TestJdkDateTimeRpcService testJdkDateTimeRpcService;

    public TestJdkDateTimeWebController(TestJdkDateTimeRpcService testJdkDateTimeRpcService) {
        this.testJdkDateTimeRpcService = testJdkDateTimeRpcService;
    }

    @PostMapping(value = "/testParamIncludeJdkDateTime.do")
    public VueElementAdminResponse fetchParamIncludeJdkDateTime(){
        TestJdkDateTimeParam testJdkDateTimeParam=new TestJdkDateTimeParam();
        testJdkDateTimeParam.setTestDate(DateUtil.formatDate(new Date()));
        testJdkDateTimeParam.setId(SmartStringUtils.getSnowFlakeStrId());
        
        VueElementAdminResponse vueElementAdminResponse=testJdkDateTimeRpcService.fetchParamIncludeJdkDateTime(testJdkDateTimeParam);
        // 错误用法 会抛出异常 java.util.LinkedHashMap cannot be cast to com.xxx.business.test.model.TestJdkDateTimeParam
        TestJdkDateTimeParam testJdkDateTimeParam1= (TestJdkDateTimeParam)vueElementAdminResponse.getData();
        log.info("test:{}",testJdkDateTimeParam1);
        return vueElementAdminResponse;
    }
}

如果我们尝试使用如下代码

TestJdkDateTimeParam testJdkDateTimeParam1= (TestJdkDateTimeParam)vueElementAdminResponse.getData();

执行会报错如下:

java.lang.ClassCastException: 

java.util.LinkedHashMap cannot be cast to com.xxx.business.test.model.TestJdkDateTimeParam

问题分析

调试我们会发现我们放入的TestJdkDateTimeParam对象变成了LinkedHashMap
在这里插入图片描述

为什么呢?

  • 在使用 Feign 进行远程调用时,如果请求或响应中包含了复杂对象(例如自定义的 POJO 类),Feign 需要将这些对象序列化成某种格式,以便在网络上进行传输。默认情况下,Feign 使用 Jackson 库来处理序列化和反序列化操作。
  • 如果您观察到 Feign 将 Object 对象的类型序列化成 LinkedHashMap,可能是由于以下原因:
    • 缺少序列化信息: 当 Feign 在进行序列化时,它需要了解对象的类型信息,以便正确地进行反序列化。如果没有正确的类型信息,Feign 可能会将对象序列化成一个类似于 LinkedHashMap 的格式,以保留一些关键信息(如字段名),但是丢失了对象的实际类型信息。
    • 泛型类型擦除: Java 的泛型在编译后会进行类型擦除,这意味着在运行时对象的具体类型信息可能会丢失。Feign 在进行序列化时可能会遇到泛型类型的擦除,导致无法准确地识别对象的实际类型。

也就是说:

在使用 Feign 进行远程调用时,如果请求或响应中包含了复杂对象(例如自定义的 POJO 类),且这个对象中包含有Object 泛型

那么 Feign 会将 Object 对象的类型序列化成 LinkedHashMap,解析时候如果不注意经常容易出现类似如下错误

java.lang.ClassCastException: 
 java.util.LinkedHashMap cannot be cast to com.xxx.business.test.model.TestJdkDateTimeParam 

修复方案

修复方案一 避免使用泛型

当使用Feign 接口调用的时候避免使用泛型,即重新定义一个Feign统一返回的VO对象:

public class VueElementAdminRpcResponseDTO implements Serializable {
    private static final long serialVersionUID = -3368531539063907497L;
    private Integer code;
    private String message;
    private String data;
    private String trackId = SmartStringUtils.getSnowFlakeStrId();
}

修复方案二 解析data泛型的时候处理

如果不想换,那么只需要解析反序列化的时候处理下也行。

解析data泛型的时候处理思路如下:

  1. 先用json工具转字符串
  2. 再反序列化成对象

参考代码如下所示:

@Slf4j
@RequestMapping(value = "/test-service/testJdkDateTimeRpcService")
@RestController
public class TestJdkDateTimeWebController {

    private final TestJdkDateTimeRpcService testJdkDateTimeRpcService;

    public TestJdkDateTimeWebController(TestJdkDateTimeRpcService testJdkDateTimeRpcService) {
        this.testJdkDateTimeRpcService = testJdkDateTimeRpcService;
    }

    @PostMapping(value = "/testParamIncludeJdkDateTime.do")
    public VueElementAdminResponse fetchParamIncludeJdkDateTime(){
        TestJdkDateTimeParam testJdkDateTimeParam=new TestJdkDateTimeParam();
        testJdkDateTimeParam.setTestDate(DateUtil.formatDate(new Date()));
        testJdkDateTimeParam.setId(SmartStringUtils.getSnowFlakeStrId());
        VueElementAdminResponse vueElementAdminResponse=testJdkDateTimeRpcService.fetchParamIncludeJdkDateTime(testJdkDateTimeParam);
        // 错误用法 会抛出异常 java.util.LinkedHashMap cannot be cast to com.xxx.business.test.model.TestJdkDateTimeParam
        // TestJdkDateTimeParam testJdkDateTimeParam1= (TestJdkDateTimeParam)vueElementAdminResponse.getData();
        // 正确用法
        // 对象序列化成字符串
        String dataJson=SmartJackSonUtils.writeObjectToJSon(vueElementAdminResponse.getData());
        // 反序列化成对象或集合
        TestJdkDateTimeParam testJdkDateTimeParam1= SmartJackSonUtils.readValueToObject(dataJson, TestJdkDateTimeParam.class);
        log.info("test:{}",testJdkDateTimeParam1);
        return vueElementAdminResponse;
    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/944070.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

深度学习卷积神经网络识别光学字符验证码,及captcha使用简单案例

深度学习卷积神经网络识别验证码 文章目录 深度学习卷积神经网络识别验证码一、引言二、导入必要的库三、防止 tensorflow 占用所有显存四、定义数据生成器并测试五、定义网络结构六、训练模型七、测试模型 一、引言 验证码识别,本身使用来判断访问网站的用户是不是…

更新netframe报错,更新.netFrame 到4.8

背景: 更新了Java程序后,启动提示我更新netframe 手动更新.netFrame 到4.8 ndp48-x86-x64-allos-enu.exe 发现报错: 继续百度解决报错。方案为: https://blog.csdn.net/i2blue/article/details/88821583 产生阻滞的问题: 你…

快手Java一面,全是基础

现在已经到了面试招聘比较火热的时候,准备面试的过程中,一定要多看面经,多自测! 今天分享的是一位贵州大学的同学分享的快手一面面经。 快手一面主要会问一些基础问题,也就是比较简单且容易准备的常规八股&#xff0…

零代码,使用 Dify 和 Laf 两分钟接入企业微信 AI 机器人

Dify 允许创建 AI 应用,并提供二次开发的能力。这里我将演示创建一个法律问答助手的 AI 应用,称作“知法”。在本篇教程中,我将指导你为“知法”接入企业微信。 前置准备 企业微信的管理员权限一个 Dify 的帐号一个 Laf 云的帐号&#xff0…

【Linux】序列化与反序列化

目录 前言 什么是应用层? 再谈"协议" 什么是序列化和反序列化 网络版计算器 整体流程实现 Sock.hpp的实现 TcpServer.hpp的实现 Protocol.hpp的实现 CalServer.cc的编写 CalClient.cc的编写 整体代码 前言 本章是属于TCP/UDP四层模型中的第一层…

opencv的使用(Ubuntu linux环境,AS jni,AS java)

最近要完成一个功能,就是把四个视频合成左右上下分布的一个视频。尝试很多方法,最终使用opencv来实现该功能。(通过opencv实现的视频好像没有声音。)研究的步骤,首先在Ubuntu环境测试,该功能是否实现。然后…

13.搬砖

目录 题目 Description Input Output 思路(归并排序) 具体步骤如下 C整体代码(含详细注释) 归并排序总结 核心步骤 代码模板 题目 Description 小张在暑假时间来到工地搬砖挣钱。包工头交给他一项艰巨的任务&#xff0…

Mavan进阶之父子模块(继承)

文章目录 Mavan 父子模块(继承)1. 父项目2. 子项目3. 父子项目的使用 Mavan 父子模块(继承) 「继承」是 Maven 中很强大的一种功能,继承可以使得子 pom 可以获得 parent 中的各项配置,可以对子 pom 进行统…

深度学习之反卷积

具体推理可以参考https://blog.csdn.net/zhsmkxy/article/details/107073350

uniapp微信小程序使用stomp.js实现STOMP传输协议的实时聊天

简介: 原生微信小程序中使用 本来使用websocket,后端同事使用了stomp协议,导致前端也需要对应修改。 如何使用 1.yarn add stompjs 2.版本 “stompjs”: “^2.3.3” 3.在static/js中新建stomp.js和websocket.js,然后在需要使用…

一文讲透超宽带(UWB)前世今生

►►►UWB大火与巨头入局 传闻已久的蔚来手机可能即将要发布了。据工信部官网显示:申请单位为蔚来移动科技有限公司、型号为N2301的手机已正式完成入网。相关认证信息显示,N2301支持UWB,可以被用作蔚来汽车的数字钥匙。 图 1 蔚来手机概念图 …

第十四课 定语从句

文章目录 前言 所有定语从句的连接词是没有意思的一、定语从句的定义和结构二、关系代词引导的定语从句1、whowho谓语(宾语)状语who系动词表语状语who助动词及物动词的过去分词 2、whomwhom主语及物动词(状语)whom主语谓语to及物动…

2023京东咖啡机行业数据分析(京东数据分析平台)

如今咖啡的渗透率越来越高,养成咖啡饮用习惯的消费者越来越多,尤其是一二线城市。同时,随着人们收入水平的提高,精致生活理念使人们对咖啡的态度从提神需求逐渐转变为社交需求,国内咖啡机市场的发展空间也逐步增大。 …

Oracle 本地客户端连接远程 Oracle 服务端并使用 c# 连接测试

这里写自定义目录标题 前言Oracle 客户端安装先决条件下载 Oracle 客户端Oracle 客户端环境变量配置 PL/SQLPL/SQL 下载PL/SQL 配置 配置远程连接tnsnames.ora 文件配置 使用 PL/SQL 连接远程数据库使用 C# 远程访问 Oracle 数据库结语 前言 最近有一个需要使用本地的 Oracle …

java内存分区

按照垃圾收集,将 Java 堆划分为**新生代 (Young Generation)和老年代(Old Generation)**两个区域, 新生代存放存活时间短的对象,而每次回收后存活的少量对象,将会逐步晋升到老年代中…

idea 创建mybatis xml文件时找不到

1、File >Settings 如图 &#xff1a; 2、添加模板&#xff1a;如下图 3、添加xml模板 如下图&#xff1a; 模板内容&#xff1a; <?xml version"1.0" encoding"UTF-8" ?> <!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//E…

微信小程序使用stomp.js实现STOMP传输协议的实时聊天

简介&#xff1a; uniapp开发的小程序中使用 本来使用websocket&#xff0c;后端同事使用了stomp协议&#xff0c;导致前端也需要对应修改。 如何使用 在static/js中新建stomp.js和websocket.js&#xff0c;然后在需要使用的页面引入监听代码发送代码即可 代码如下&#x…

燃气管网监测系统,提升城市燃气安全防控能力

燃气是我们日常生活中不可或缺的能源&#xff0c;但其具有易燃易爆特性&#xff0c;燃气安全使用、泄漏监测尤为重要。当前全国燃气安全事故仍呈现多发频发态势&#xff0c;从公共安全的视角来看&#xff0c;燃气已成为城市安全的重大隐忧&#xff01;因此&#xff0c;建立一个…

Linux 终端命令行 产品介绍

Linux命令手册内置570多个Linux 命令&#xff0c;内容包含 Linux 命令手册。 【软件功能】&#xff1a; 文件传输 bye、ftp、ftpcount、ftpshut、ftpwho、ncftp、tftp、uucico、uucp、uupick、uuto、scp备份压缩 ar、bunzip2、bzip2、bzip2recover、compress、cpio、dump、gun…

计算机毕设 基于深度学习的植物识别算法 - cnn opencv python

文章目录 0 前言1 课题背景2 具体实现3 数据收集和处理3 MobileNetV2网络4 损失函数softmax 交叉熵4.1 softmax函数4.2 交叉熵损失函数 5 优化器SGD6 最后 0 前言 &#x1f525; 这两年开始毕业设计和毕业答辩的要求和难度不断提升&#xff0c;传统的毕设题目缺少创新和亮点&a…