SpringMvc 与 Lombok 碰撞导致 JSON 反序列化失败
SpringMvc 与 Lombok 中 JSON 反序列化失败
错误复现_1
@Data
public class User{private Long id;private boolean isOk;
}@RequestMapping
public R<User> getUser(@RequestBody User user){return R.success(user);
}// 前端传参 - {"id": 123456789,"isOk": true}
// 后端返回 - {"id": 123456789,"isOk": false}
排查分析_1
查看 User 类 class 文件。
public class User{pirvate Long id;private boolean isOk;public User() {}public Long getId() { return this.id; }public boolean isOk() { return this.isOk; }public void setId(final Long id) { this.id = id; }public void setOk(final boolean isOk) { this.isOk = isOk; } }
提出猜测:Lombok 对于 boolean 类型生成的 Getter/Setter 方法与其他类型不同,该原因导致的数据不一致。
错误复现_2
@Data
public class User{private Long id;private String Name;private Long cId;
}// 前端传参 - {"id": 1,"Name": "LXL","cId": 2}@RequestMapping
public void getUser(@RequestBody User user){System.out.println(user.getId()); // 1System.out.println(user.getName()); // nullSystem.out.println(user.getCId()); // null
}
排查分析_2
查看 User 类 class 文件。
public class User {private Long id;private String Name;private Long cId;public User() {}public Long getId() { return this.id; }public String getName() { return this.Name; }public Long getCId() { return this.cId; }public void setId(final Long id) { this.id = id; }public void setName(final String Name) { this.Name = Name; }public void setCId(final Long cId) { this.cId = cId; } }
提出猜测:反序列化时,由于某种原因导致无法正常赋值。
揭开谜团
结合上述两个猜测,去了解了 SpringMvc 的反序列化机制、Lombok 的代码生成机制。
先说一下 SpringMvc 的 @RequestBody 注解:
- SpringMvc 中通过 @RequestBody 注解实现将 json 数据转成 java 对象。
- 处理 @RequestBody 注解时,内部使用 jackson 框架完成该反序列化过程。
接下来是 Jackson 框架的反序列化操作步骤:
- 仅有全参数构造器时,通过调用该构造器,映射 JSON 属性与 Construction 参数列表完成对象的实例化。
- 有无参数构造器时,优先使用无参数构造器 + Getter/Setter 方法完成序列化与反序列化。调用反序列化的目标类的无参构造函数,构造一个 java 对象。然后调用该类的成员变量的 set 方法,为该对象的每一个成员变量赋值。
- Jackson 遵守了
JavaBean
的规范:
- 首字母为大写的属性名(如:Name, URL, SuV…),这种属性名直接忽略不注入。
- 第一个字母是小写,第二个字母大写的情况(如:pId, sUV…),在生成 Getter/Setter 的时,直接在前面加上 set/get,比如 pId 生成 setpId()/getpId(),所以 pId 属性在注入的时候会寻找 setpId() 方法,而不是 setPId() 。
最后是 Lombok 的 Getter/Setter 生成机制:
- 当成员变量为 boolean 类型时,属性名为 isXxx 生成的 Getter/Setter 方法的方法名为 isXxx/setXxx。
- 其他基本类型与所有引用数据类型,属性名为 aaBb 生成的 Getter/Setter 方法的方法名为 getAaBb/setAaBb,例如 isXxx 生成 getIsXxx/SetIsXxx。
这几个知识点就可以解决错误 1、错误 2 啦!!!
- 错误 1 造成原因:为属性名 isOk 查找 Setter 方法时,找不到 setIsOk,所以无法注入,使用默认值 false。
- 错误 2 造成原因:属性名 Name 不符合 JavaBean 规范被直接忽略注入;属性名 cId 查找的 Setter 方法名应该为 setcId,而 Lombok 生成的是 setCId,也是注入不了的。
方案与总结
- 规范且合理制定成员变量名称。
- 尽量使用包装类,既可以符合 Java 语言面向对象的特性,同时可以避免 Lombok 生成的 Setter/Getter 与 Jackson 框架规则间的冲突。
- 上述两种方案不适合的话,可以考虑手动生成 Setter/Getter 方法。
- 通过 @JsonProperty 显式指定 JSON 属性与 Java 属性的对应关系。
相关文章:
SpringMvc 与 Lombok 碰撞导致 JSON 反序列化失败
SpringMvc 与 Lombok 中 JSON 反序列化失败 错误复现_1 Data public class User{private Long id;private boolean isOk; }RequestMapping public R<User> getUser(RequestBody User user){return R.success(user); }// 前端传参 - {"id": 123456789,"i…...
怎么样显卡叠加,什么是NVIDIA 显卡 非公、公版、涡轮卡
1、显存叠加的问题,因为这个跟是否是深度学习无关: 先说一下显存叠加的问题,因为这个跟是否是深度学习无关:一台机器有多张显卡,显存不会叠加!显卡里面包含了显存、cache、计算单元、通信等,每…...
CentOS安装Elasticsearch集群
前言 之前使用的ES集群是其他公司维护,没有机会安装,后来做其他项目,终于有机会安装ES集群,简单记录一下备用 一、安装jdk 安装jdk1.8就可以,可以参考另一篇文章,这里就不细说了 二、修改系统参数 如果在…...
计算机专业毕业生指南
在大四毕业时,完成计算机毕业设计需要一定的计划和组织。以下是一些建议,帮助你在三个月内快速完成毕业设计: 选择一个合适的主题: 选择一个你感兴趣的主题,这将激发你的热情,使你更有动力完成项目。 确保…...

Springboot集成Docker并将镜像推送linux服务器
案例使用springboot项目,在IDEA 中集成Docker生成镜像,并将镜像发布到linux服务器 具体步骤如下: 1、Centos7安装Docker 更新系统的软件包列表 sudo yum update安装Docker所需的软件包和依赖项: sudo yum install docker完成…...

数字孪生与GIS:智慧城市的未来之路
数字孪生和地理信息系统(GIS)是两个在现代科技中崭露头角的概念,它们的融合为智慧城市项目带来了革命性的机会。本文将解释数字孪生为何需要融合GIS,并以智慧城市项目为例进行说明。 数字孪生是一种虚拟模型,它精确地…...

nas汇编程序的调试排错方法
nas汇编程序的调试排错方法: 1、查找是哪一步错了 2、查看对应的*.lst文件,本例中是"asmhead.lst" 3、根据*.lst文件的[ERROR #002]提示查看源码,改错。 4、重新运行编译,OK 1、查找是哪一步错了: nask.ex…...
【网络安全带你练爬虫-100练】第21练:批量获取文件夹中文件名
目录 一、目标1:使用python爬取指定文件夹中的文件名 二、目标2:在文件夹指定目录打开命令行 一、目标1:使用python爬取指定文件夹中的文件名 方法一:使用os模块 将/path/to/folder替换为实际的文件夹路径。os.listdir()函数用…...

Unittest自动化测试框架vs Pytest自动化测试框架
引言 前面一篇文章Python单元测试框架介绍已经介绍了python单元测试框架,大家平时经常使用的是unittest,因为它比较基础,并且可以进行二次开发,如果你的开发水平很高,集成开发自动化测试平台也是可以的。而这篇文章…...

PHP8的数组-PHP8知识详解
今天开始学习数组, 本文主要讲了三点:什么是数组、php8中数组的改进、数组函数。 一、什么是数组 在PHP8中,数组是非常重要的数据类型。相对于其他的数据类型,数组更像一种结构,而这种结构可以储存一系列数值。 数组…...
数据仓库_维度表的两大分类
最近看一篇文章对维度表进行了分类,记录一下。 维度表主要分为两类高基数维度表和低基数维度表。 高基数维度数据 一般是用户资料表、商品资料表类似的资料表。数据量可能是千万级或者上亿级别。 低基数维度数据 一般是配置表,比如枚举值对应的中文含…...

4、DVWA——文件包含
文章目录 一、文件包含概述二、low2.1 源码分析2.2 通关分析 三、medium3.1 源码分析3.2 通关思路 四、high4.1 源码分析4.2 通关思路 五、impossible 一、文件包含概述 文件包含是指当服务器开启allow_url_include选项时,就可以通过php的某些特性函数(i…...
产品经理如何进行需求管理
产品经理在进行需求管理时,可以遵循以下步骤: 1. 确定需求目标:明确产品的愿景和目标,确定需求管理的方向和重点。 2. 收集需求:与利益相关者(包括用户、业务部门、技术团队等)沟通,…...

【从0学习Solidity】2. 值类型详解
Solidity极简入门: 2. 值类型 博主简介:不写代码没饭吃,一名全栈领域的创作者,专注于研究互联网产品的解决方案和技术。熟悉云原生、微服务架构,分享一些项目实战经验以及前沿技术的见解。关注我们的主页,探索全栈开发…...

框架分析(9)-Hibernate
框架分析(9)-Hibernate 专栏介绍Hibernate特性对象关系映射(ORM)数据库连接和事务管理查询语言(HQL)缓存机制透明的持久化操作对象的延迟加载事务管理 优缺点优点简化数据库操作跨数据库平台高度可定制性缓…...

JavaScript中的原型链(prototype chain)
聚沙成塔每天进步一点点 ⭐ 专栏简介⭐ JavaScript中的原型链⭐ 写在最后 ⭐ 专栏简介 前端入门之旅:探索Web开发的奇妙世界 记得点击上方或者右侧链接订阅本专栏哦 几何带你启航前端之旅 欢迎来到前端入门之旅!这个专栏是为那些对Web开发感兴趣、刚刚踏…...

设计模式之代理模式与外观模式
目录 代理模式 简介 优缺点 角色职责 实现 运用场景 外观模式 简介 角色职责 优缺点 实现 使用场景 代理模式 简介 由于某些原因需要给某对象提供一个代理以控制对该对象的访问。这时,访问对象不适合或者不能直接引用目标对象,代理对象作为…...

动手学深度学习(四)多层感知机
目录 一、多层感知机的从零开始实现 1.1 初始化模型参数 1.2 实现Relu函数 1.3 实现模型 1.4 训练 二、多层感知机的简洁实现 2.1 实现模型 2.2 训练 三、模型选择 3.1 训练误差和泛化误差 3.2 验证数据集和测试数据集 3.3 过拟合和欠拟合 3.4 代码实现 3.4.1 生…...

融云出海:社交泛娱乐出海,「从 0 到 1」最全攻略
9 月 21 日,融云直播课社交泛娱乐出海最短变现路径如何快速实现一款 1V1 视频社交应用? 欢迎点击上方小程序报名~ 本期我们翻到《地图》的实践篇,从赛道/品类选择、目标地区适配、用户增长、变现模式、本地化运营、跨国团队管理等方面完整描绘…...

生成式人工智能促使社会转变
作者:JEFF VESTAL 了解 Elastic 如何处于大型语言模型革命的最前沿 – 通过提供实时信息并将 LLM 集成到数据分析的搜索、可观察性和安全系统中,帮助用户将 LLM 提升到新的高度。 iPhone 社会转变:新时代的黎明 曾几何时,不久前…...
基于算法竞赛的c++编程(28)结构体的进阶应用
结构体的嵌套与复杂数据组织 在C中,结构体可以嵌套使用,形成更复杂的数据结构。例如,可以通过嵌套结构体描述多层级数据关系: struct Address {string city;string street;int zipCode; };struct Employee {string name;int id;…...
k8s从入门到放弃之Ingress七层负载
k8s从入门到放弃之Ingress七层负载 在Kubernetes(简称K8s)中,Ingress是一个API对象,它允许你定义如何从集群外部访问集群内部的服务。Ingress可以提供负载均衡、SSL终结和基于名称的虚拟主机等功能。通过Ingress,你可…...

DBAPI如何优雅的获取单条数据
API如何优雅的获取单条数据 案例一 对于查询类API,查询的是单条数据,比如根据主键ID查询用户信息,sql如下: select id, name, age from user where id #{id}API默认返回的数据格式是多条的,如下: {&qu…...

IoT/HCIP实验-3/LiteOS操作系统内核实验(任务、内存、信号量、CMSIS..)
文章目录 概述HelloWorld 工程C/C配置编译器主配置Makefile脚本烧录器主配置运行结果程序调用栈 任务管理实验实验结果osal 系统适配层osal_task_create 其他实验实验源码内存管理实验互斥锁实验信号量实验 CMISIS接口实验还是得JlINKCMSIS 简介LiteOS->CMSIS任务间消息交互…...
Python ROS2【机器人中间件框架】 简介
销量过万TEEIS德国护膝夏天用薄款 优惠券冠生园 百花蜂蜜428g 挤压瓶纯蜂蜜巨奇严选 鞋子除臭剂360ml 多芬身体磨砂膏280g健70%-75%酒精消毒棉片湿巾1418cm 80片/袋3袋大包清洁食品用消毒 优惠券AIMORNY52朵红玫瑰永生香皂花同城配送非鲜花七夕情人节生日礼物送女友 热卖妙洁棉…...

【分享】推荐一些办公小工具
1、PDF 在线转换 https://smallpdf.com/cn/pdf-tools 推荐理由:大部分的转换软件需要收费,要么功能不齐全,而开会员又用不了几次浪费钱,借用别人的又不安全。 这个网站它不需要登录或下载安装。而且提供的免费功能就能满足日常…...

GitFlow 工作模式(详解)
今天再学项目的过程中遇到使用gitflow模式管理代码,因此进行学习并且发布关于gitflow的一些思考 Git与GitFlow模式 我们在写代码的时候通常会进行网上保存,无论是github还是gittee,都是一种基于git去保存代码的形式,这样保存代码…...
C++课设:简易日历程序(支持传统节假日 + 二十四节气 + 个人纪念日管理)
名人说:路漫漫其修远兮,吾将上下而求索。—— 屈原《离骚》 创作者:Code_流苏(CSDN)(一个喜欢古诗词和编程的Coder😊) 专栏介绍:《编程项目实战》 目录 一、为什么要开发一个日历程序?1. 深入理解时间算法2. 练习面向对象设计3. 学习数据结构应用二、核心算法深度解析…...
Caliper 负载(Workload)详细解析
Caliper 负载(Workload)详细解析 负载(Workload)是 Caliper 性能测试的核心部分,它定义了测试期间要执行的具体合约调用行为和交易模式。下面我将全面深入地讲解负载的各个方面。 一、负载模块基本结构 一个典型的负载模块(如 workload.js)包含以下基本结构: use strict;/…...

android RelativeLayout布局
<?xml version"1.0" encoding"utf-8"?> <RelativeLayout xmlns:android"http://schemas.android.com/apk/res/android"android:layout_width"match_parent"android:layout_height"match_parent"android:gravity&…...