不过……事情并没有那么简单。后端不会将所有的报文都作为 POJO 的字段,会存在一些动态的字段,用 Map 存储。可 Map 存储的这些字段,Jackson 在输出时不会转为小写,还是保留原有的大写形式,这样就会导致给前端的字段,虽然都是匈牙利风格,但有些大写有些小写……虽然前端不知道打不打人,但我可不敢这么玩
Jackson 的匈牙利命名法处理
其实 Jackson 序列化之后转小写的原因也很好解释,Java 的设计规范,就是 Bean 中的属性用 private 修饰,然后提供 getter/setter 来提供读取/写入。那么在序列化时,Jackson 通过字段的 Getter 来访问属性值,甚至用 Getter 方法来解析属性名。
Java 的 getter 方法命名标准是,将小写驼峰转大写驼峰,Jackson 在通过 getter 方法名解析字段名时,将 getNID 解析为 nid 了,所以导致最终输出的字段名为小写的 nid。
FastJson 的匈牙利命名法处理
本来是想定制化一下 Jackson 的命名处理的,但想了一下觉得没必要,毕竟是我们命名不标准,何必去改这个命名处理机制呢,划不来。
所以我又尝试着换一种 JSON 库去处理这个命名问题,先试试阿里的 FastJSON,看看这个国产库的处理怎么样:
{
“cTitle”:“Effective JAVA”,
“nId”:1
}
看到这个序列化结果时,我差点把我键盘上的 Backspace 按断了……同样是通过 getter 方法解析属性名,两个库的解析规则还能不一样……
在 FastJson 里,c 是小写了,可 Title 里的 T 还是大写,@#¥%……&此处省略100字……
冷静一下之后,心里默念了几遍:“不怪别人,是我们自己的命名问题,不符合标准人家怎么解析都不关你事……”
不过 JAVA 的生态这么好,JSON 库也不止这两个,再换一个就是,Google 的 Gson 也很不错嘛!
Gson 的匈牙利命名法
于是我又换成了 Gson,配置完 Spring MVC Gson Converter 之后,输出结果:
{
“NId”:1,
“CTitle”:“Effective JAVA”
}
终于换到一个能正常显示原始字段名的 JSON 库了,不过它既然能保持原有字段名,而不是 getter 里解析的属性名,那么它肯定不是解析 getter 方法名的
于是我又去翻了下 Gson 的源码,发现它是直接 getDeclaredFields()
,然后makeAccessible
,最后直接通过 Field.getValue
的方式直接获取属性值的。
相比 Jackson 和 FastJson 里通过 getter 获取属性列表,然后通过调用 getter 方法来获取属性值的方法来说,强制访问私有属性这种做法还是太暴力了,不过我喜欢,至少它能轻松解决了我的问题
其他的序列化问题
除了 JSON 这种文本形式的序列化之外,一些二进制的序列化也会有这个尴尬的问题,获取属性列表/属性值,到底是用解析 getter 方法的方式,还是直接 makeAccessible 暴力访问私有属性呢?
这个我测试了一下,比如在 Dubbo 的默认序列化方式(Dubbo 简化的Hession2)中,仍然是 getDeclaredFields
,然后访问私有属性
在 JDK 的内置序列化 ObjectOutputStream 中,也是 getDeclaredFields
,然后访问私有属性。
不过这种 getDeclaredFields ,然后访问私有属性值的方式,也会有一些劣势。比如在遇到代码混淆时,私有属性的值会被全部打乱,而 public 的方法却不会,所以在遇到混淆的代码时,这种方式就会乱套了,而通过 getter 方法解析的方式就不会有问题。
所以吧,这个获取属性的方式并没有对错,怎么都可以,不过我认为还是应该通过 getter/setter 的方式来操作,符合 JAVA 的规范。
感谢@用户3323102545477 的提醒,Jackson 很强大,支持配置属性的获取方式,可以配置 Visibility
来实现只通过 Field
而不通过 getter
来获取属性:
@JsonAutoDetect(fieldVisibility = JsonAutoDetect.Visibility.ANY,
getterVisibility = JsonAutoDetect.Visibility.NONE)
public class Book {
private Integer NId = 1;
private String CName = “John”;
}
全局配置更方便:
ObjectMapper objectMapper = new ObjectMapper();
// 配置 field 为可见
objectMapper.setVisibility(PropertyAccessor.FIELD, JsonAutoDetect.Visibility.ANY);
// 配置 getter 不可见
objectMapper.setVisibility(PropertyAccessor.GETTER, JsonAutoDetect.Visibility.NONE);
Java 里访问私有属性值,标准的方式是通过 getter 方法,但还是提供了一个 makeAccessible 操作,可以让我们直接访问私有属性或者私有方法。
小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。
深知大多数初中级Java工程师,想要提升技能,往往是自己摸索成长,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!
因此收集整理了一份《2024年最新Java开发全套学习资料》送给大家,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频
如果你觉得这些内容对你有帮助,可以添加下面V无偿领取!(备注Java)
最后
手绘了下图所示的kafka知识大纲流程图(xmind文件不能上传,导出图片展现),但都可提供源文件给每位爱学习的朋友
如果你觉得这些内容对你有帮助,可以添加下面V无偿领取!(备注Java)
[外链图片转存中…(img-U7yBRfBJ-1710421131152)]
最后
手绘了下图所示的kafka知识大纲流程图(xmind文件不能上传,导出图片展现),但都可提供源文件给每位爱学习的朋友
[外链图片转存中…(img-i92mzRQj-1710421131152)]