Spring 中类似 aBbb 单字母单词序列化与反序列问题

文章目录

  • 前言
  • 代码准备
    • 问题排查
    • lombok
    • 自定义生成 `get、set`
  • 结合源码解析
    • 使用 `lombok`
    • 使用 `lombok` 自定义生成 `user 对象 get、set` 方法
  • 如何解决
    • 使用注解 `@JsonProperty("aTest")`
    • 自定义实现符合 `Spring` 规范的 `get set` 方法
  • 个人简介

前言

  • 最近在使用 spring boot mvc 实现 HTTP 接口时出现了大小写异常转换的神秘现象,比如下面的案例:
@Data
public class User {private int id;private String name;private String aTest;
}请求参数:
{"name": "小明","aTest": "测试" 
}响应参数:
{"id": 1,"name": "小明","atest": null  // aTest 未成功接收
}1、前端字段序列化异常2、aTest 字段被序列化为了 atest

代码准备

  • Spring-boot-parent 2.6.4
@Data
public class User {private int id;private String name;private String aTest;public User(int id, String name, String aTest) {this.id = id;this.name = name;this.aTest = aTest;}
}@Repository
public class UserRepository {public User createUser(User user) {System.out.println(user);return user;}
}@RestController
public class UserController {@Autowiredprivate UserRepository userRepository;@PostMapping("/users")public User createUser(@RequestBody User user) {return userRepository.createUser(user);}
}

问题排查

  • 经过一系列排查发现是对象序列化和反序列化导致的问题,一个是使用 lombok 生成 get、set 方法,一个使用自定义生成 get、set 方式实现,下面我们来看一下两种情况的差异:

lombok

  • User 对象使用 lombok 生成 get、set 方法
@Data
public class User {private int id;private String name;private String aTest;
}
  • 测试结果:
POST http://localhost:8080/users
Content-Type: application/json{"name": "小明","aTest": "测试"
}// 打印日志 aTest 字段未被成功接收
User(id=0, name=小明, aTest=null)// 响应日志 aTest 字段被转换为 atest
{"id": 1,"name": "小明","atest": null
}
  • 可以发现接口请求传递过来的 aTest 没有被正常反序列,响应时 aTest 字段被序列为了 atest

自定义生成 get、set

  • 自定义生成 user 对象 get、set 方法。
public class User {private int id;private String name;private String aTest;public User(int id, String name, String aTest) {this.id = id;this.name = name;this.aTest = aTest;}public String getName() {return name;}public void setName(String name) {this.name = name;}public String getaTest() {return aTest;}public void setaTest(String aTest) {this.aTest = aTest;}@Overridepublic String toString() {return "User{" +"id=" + id +", name='" + name + '\'' +", aTest='" + aTest + '\'' +'}';}
}
  • 测试结果:
POST http://localhost:8080/users
Content-Type: application/json{"name": "小明","aTest": "测试"
}// 打印日志 aTest 字段被成功接收
User{id=0, name='小明', aTest='测试'}// 响应日志 aTest 字段被转为预期的 aTest
{"id": 1,"name": "小明","aTest": "测试"
}
  • 可以发现请求时 aTest 被正常解析,响应时 aTest 被序列化为预期的 aTest

结合源码解析

  • 这里我们可以对比 lombok 和我们自定义生成 get、set 方法的差异:
// lombokpublic String getATest() {return this.aTest;}public void setATest(final String aTest) {this.aTest = aTest;}// 自定义public String getaTest() {return aTest;}public void setaTest(String aTest) {this.aTest = aTest;}
  • 我们知道 Spring 默认使用 jackson 进行序列化和反序列,在构建 BeanDeserializer 时会通过方法和字段获取对应的 属性properties,由于 Spring 和 lombokJavaBeans 规范的定义理解并不一致导致识别字段结果不同,具体可以参考:https://github.com/projectlombok/lombok/issues/757

使用 lombok

  • 我们先看看,lombok 生成的 BeanDeserializer
  • com.fasterxml.jackson.databind.deser.BeanDeserializerFactory#buildBeanDeserializer 中我们可以看到调用了 buildBeanDeserializer 生成 BeanDeserializer

  • 一直断点,我们可以来到 com.fasterxml.jackson.databind.introspect.POJOPropertiesCollector#collectAll 获取 properties map,这里是重点:

  • 执行 _addFields、_addMethods 我们推断出了来 4 个字段:

  • 这里为什么是4个呢?因为 lombokSpring jacksonJavaBeans 规范的定义理解不一致,导致从方法中推断出了 atest 字段。
  • 然后执行 _removeUnwantedProperties 字段去除了 aTest 字段,因为它是不可见的。

使用 lombok 自定义生成 user 对象 get、set 方法

  • 我们采取自定义的写法生成 user 对象 get、set 方法,对象属性可以正常被识别:

如何解决

  • 知道了问题产生原因,解决就很简单了,只要让我们字段属性被正常推断即可。

使用注解 @JsonProperty("aTest")

自定义实现符合 Spring 规范的 get set 方法

    public String getaTest() {return aTest;}public void setaTest(String aTest) {this.aTest = aTest;}

个人简介

👋 你好,我是 Lorin 洛林,一位 Java 后端技术开发者!座右铭:Technology has the power to make the world a better place.

🚀 我对技术的热情是我不断学习和分享的动力。我的博客是一个关于Java生态系统、后端开发和最新技术趋势的地方。

🧠 作为一个 Java 后端技术爱好者,我不仅热衷于探索语言的新特性和技术的深度,还热衷于分享我的见解和最佳实践。我相信知识的分享和社区合作可以帮助我们共同成长。

💡 在我的博客上,你将找到关于Java核心概念、JVM 底层技术、常用框架如Spring和Mybatis 、MySQL等数据库管理、RabbitMQ、Rocketmq等消息中间件、性能优化等内容的深入文章。我也将分享一些编程技巧和解决问题的方法,以帮助你更好地掌握Java编程。

🌐 我鼓励互动和建立社区,因此请留下你的问题、建议或主题请求,让我知道你感兴趣的内容。此外,我将分享最新的互联网和技术资讯,以确保你与技术世界的最新发展保持联系。我期待与你一起在技术之路上前进,一起探讨技术世界的无限可能性。

📖 保持关注我的博客,让我们共同追求技术卓越。

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

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

相关文章

Linux下Qt生成程序崩溃文件

文章目录 1.背景2.Qt编译生成程序2.1.profile模式的本质 3.执行程序,得到core文件4.代码定位4.1.直接使用gdb4.2.使用QtCreator 5.总结6.题外话6.1.profile模式和debug模式的区别 1.背景 在使用Qt时,假如在windows,当软件崩溃时,…

C++11右值引用

传统的C语法中就有引用的语法,而C11中新增了的右值引用语法特性,所以从现在开始我们之前学习的引用就叫做左值引用。无论左值引用还是右值引用,都是给对象取别名。 左值与左值引用 左值是一个表示数据的表达式(如变量名或解引用的指针)&…

C++面试经典问题

常见问题:智能指针、多态、虚函数、STL原理、链表、排序、二叉树、设计模式、线程进程、内存 对象所有权 在接触智能指针之前首先要理解对象的所有权是什么,在这之前我们总是用new和delete来进行内存的申请与释放,在这种堆内存分配的方式中…

springboot国际化多语言

1,新建国际化多语言文件 在resources目录下新建 messages.properties 其他语言的文件 编辑messages.properties文件,下方从text切换到Resource Bundle ,即可对照着编辑多语言文件 (如果没有找到Resource Bundle,先在settings->plugins中安装Resource Bundle Editor) 2,配…

Lumos学习王佩丰Excel第二讲:单元格格式设置

今天学会GIF录制了,分享知识会更简便一些,话不多说,开始吧~ 一、美化表格 1、设置单元格格式的路径 从菜单栏进入: 选中区域(单元格)- 右键“设置单元格格式”: 2、合并单元格 合并一行 批量…

5.3 用栈翻转数组,动态规划求斐波那契数列

5.3 用栈翻转数组,动态规划求斐波那契数列 1. 用栈翻转数组 assume cs:code,ds:data,ss:stack data segmentarr dw 1111h,2222h,3333h,4444h,5555h,6666h,7777h,8888hres db 800 dup(0) data endsstack segmentdb 100 dup(0) stack endscode segmentstart:mov ax,…

YOLOv8模型剪枝实战:Network Slimming网络瘦身方法

课程链接:YOLOv8模型剪枝实战:Network Slimming网络瘦身方法_在线视频教程-CSDN程序员研修院 YOLOv8是一个当前非常流行的目标检测器,本课程使用Network Slimming(网络瘦身)剪枝方法对YOLOv8进行模型剪枝,…

力扣347. 前 K 个高频元素

思路:记录元素出现的次数用map; 要维护前k个元素,不至于把所有元素都排序再取前k个,而是新建一个堆,用小根堆存放前k个最大的数。 为什么是小根堆?因为堆每次出数据时只出堆顶,每次把当前最小的…

手动实现Tomcat底层机制+自己设计Servlet

文章目录 1.Tomcat整体架构分析自己理解 2.第一阶段1.实现功能2.代码1.TomcatV1.java 3.调试阶段1.阻塞在readLine导致无法返回结果 4.结果演示 3.第二阶段1.实现功能2.代码1.RequestHander.java2.TomcatV2.java 3.调试阶段1.发现每次按回车会接受到两次请求 4.结果演示 4.第三…

[dvwa] Command Injection

命令注入 0x01 low 没有过滤,直接利用 127.0.0.1 && ip a 函数 php_uname(mode) 动态地检查服务器的操作系统 ‘s’:操作系统名称 ‘n’:网络主机名 ‘r’:操作系统发行版本号 ‘v’:操作系统版本 ‘m’&…

书籍《笔记的方法》读后感

读完《笔记的方法》有几周的时间,书里有些记录的内容,觉得非常有价值的,自己的观点,当下读书,其实并没有那么高大尚,就是存粹陶冶下情操,读书还是有一定作用的,毕竟看书只能慢慢来&a…

淘宝API接口详解:如何高效利用API进行电商开发

淘宝API接口详解:如何高效利用API进行电商开发 请求示例,API接口接入Anzexi58 在电商行业蓬勃发展的今天,淘宝作为国内最大的电商平台之一,为商家和开发者提供了丰富的API接口。这些接口使得电商开发变得更加高效和便捷。本文将详…

【算法篇】三道题理解算法思想——认识BFS

BFS(宽搜) 宽度优先遍历和深度优先遍历组成了大家熟悉的搜索算法,这两种算法也是蓝桥杯之类竞赛题的常考思想,正巧马上蓝桥杯临近,博主也是刷了很多BFS相关的题型,在这篇文章中会从力扣上选取三道简单的宽搜…

一键无痕清理:高效删除Mac文件夹,释放宝贵存储空间

在当今重视隐私的时代,当转让或出借Mac电脑时,确保个人文件和敏感信息彻底清除至关重要。常规删除Mac上的文件和文件夹仅使数据看似消失,实际上它们仍驻留在硬盘上,存在被数据恢复软件找回的风险。为实现不可逆的删除效果&#xf…

【Linux】指令

1. 简单指令 whoami 显示当前登入账号名 ls /home 现在有的用户名 adduser 用户名 新加用户(必须在root目录下) passwd 用户名 给这个用户设置密码 userdel -r 用户名 删除这个用户 pwd 显示当前所处路径 stat 文件名 / 文件夹名 显示文件状…

五分钟快速搭建五金行业小程序商城教程解析

作为五金行业的从业者,你可能想要拓展线上业务,提供更方便快捷的购物体验给顾客。而小程序商城成为了一种非常受欢迎的方式。但是,你可能觉得不懂代码无法实现这样的小程序商城。现在,我将通过以下步骤,教你如何在五分…

TikTok防关联封号及操作需注意什么?

现在Tiktok对账户的管控一直非常严格。在运营Tiktok账户时,应该注意哪些方面来减少账户损失?以下是几个账户可能出现问题的原因。 网络环境问题 1.Tiktok账户对账户有严格的控制。我们经营Tiktok账户,手机应该模拟海外环境。一旦平台发现我…

全网短剧搜索前端源码开源分享可改自己的接口

全网短剧搜索前端源码 内含7000短剧资源(不支持在线播放) 源码全开源,可以修改成自己的接口 178、226、347行修改 源码免费下载地址抄笔记 (chaobiji.cn)https://chaobiji.cn/

linux 文件提权|属性修改

文章目录 suid(set uid)添加文件属性查看文件属性i (immutable) umask suid(set uid) 让文件在执行的时候具有属主(对应文件 user )的权限 chmod 7744 temp.txt 第一位的7表示权限位…

数据库的基本使用

一、数据库的简介 RDBMS简介: Relational Database Management System,通过表来表示关系类型。当前主要使用两种类型的数据库:关系型数据库和非关系型数据库。所谓的关系型数据库RDBMS是建立在关系模型基础上的数据库,借助于集合代数等数学概念和方法来…