宜昌永东建设网站,做网站买空间,最好的做法是(),昆明网站优化公司文章目录 前言代码准备问题排查lombok自定义生成 get、set 结合源码解析使用 lombok使用 lombok 自定义生成 user 对象 get、set 方法 如何解决使用注解 JsonProperty(aTest)自定义实现符合 Spring 规范的 get set 方法 个人简介 前言
最近在使用 spring boot mvc… 文章目录 前言代码准备问题排查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(id0, name小明, aTestnull)// 响应日志 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{id0, 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 和 lombok 对 JavaBeans 规范的定义理解并不一致导致识别字段结果不同具体可以参考https://github.com/projectlombok/lombok/issues/757。
使用 lombok
我们先看看lombok 生成的 BeanDeserializercom.fasterxml.jackson.databind.deser.BeanDeserializerFactory#buildBeanDeserializer 中我们可以看到调用了 buildBeanDeserializer 生成 BeanDeserializer 一直断点我们可以来到 com.fasterxml.jackson.databind.introspect.POJOPropertiesCollector#collectAll 获取 properties map这里是重点: 执行 _addFields、_addMethods 我们推断出了来 4 个字段 这里为什么是4个呢因为 lombok 和 Spring jackson 对 JavaBeans 规范的定义理解不一致导致从方法中推断出了 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编程。 我鼓励互动和建立社区因此请留下你的问题、建议或主题请求让我知道你感兴趣的内容。此外我将分享最新的互联网和技术资讯以确保你与技术世界的最新发展保持联系。我期待与你一起在技术之路上前进一起探讨技术世界的无限可能性。 保持关注我的博客让我们共同追求技术卓越。