有一位同事说使用 fastjson 进行 JSON 序列化存储到数据库后,发现 JSON 字符串“莫名其妙地”多了一些属性!帮看了下代码,看到基本类型的布尔类型以 is 开头的属性,再看到 fastjson ,就有点想笑。
复现
定义 MyClass
public class MyClass {
// boolean 类型的属性
private boolean isActive;
private boolean valid;
// int 类型的属性
private int id;
// 默认构造器
public MyClass() {
}
// 带有所有属性的构造器
public MyClass(boolean isActive, boolean valid, int id) {
this.isActive = isActive;
this.valid = valid;
this.id = id;
}
// isActive 的 getter 和 setter 方法
public boolean isActive() {
return isActive;
}
public void setActive(boolean isActive) {
this.isActive = isActive;
}
// valid 的 getter 和 setter 方法
public boolean getValid() {
return valid;
}
public void setValid(boolean valid) {
this.valid = valid;
}
// id 的 getter 和 setter 方法
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
}
编写测试代码:
import com.alibaba.fastjson.JSON;
public class MyClassMain {
public static void main(String[] args) {
// 创建 MyClass 对象
MyClass myClass = new MyClass(true, false, 123);
// 使用 fastjson 序列化对象
String jsonString = JSON.toJSONString(myClass);
// 打印 JSON 字符串
System.out.println(jsonString);
}
}
结果:
{“active”:true,“id”:123,“valid”:false}
我们发现多了一个 active 属性,少了一个 isActive 属性!
推荐一个开源免费的 Spring Boot 实战项目:
https://github.com/javastacks/spring-boot-best-practice
分析
通过调试可以发现,问题出现在下面这个函数:
com.alibaba.fastjson.serializer.SerializeConfig#createJavaBeanSerializer(java.lang.Class>)
public final ObjectSerializer createJavaBeanSerializer(Class> clazz) {
String className = clazz.getName();
long hashCode64 = TypeUtils.fnv1a_64(className);
if (Arrays.binarySearch(denyClasses, hashCode64) >= 0) {
throw new JSONException("not support class : " + className);
}
// 关键
SerializeBeanInfo beanInfo = TypeUtils.buildBeanInfo(clazz, null, propertyNamingStrategy, fieldBased);
if (beanInfo.fields.length == 0 && Iterable.class.isAssignableFrom(clazz)) {
return MiscCodec.instance;
}
return createJavaBeanSerializer(beanInfo);
}
而 buildBeanInfo 的关键是com.alibaba.fastjson.util.TypeUtils#computeGetters
public static List computeGetters(Class> clazz, //
JSONType jsonType, //
Map aliasMap, //
Map fieldCacheMap, //
boolean sorted, //
PropertyNamingStrategy propertyNamingStrategy //
){
// 省略部分代码
if(methodName.startsWith("is")){
if(methodName.length()
其实 fastjson 通过反射虽然有能力识别真实的属性名,但是实际操作时会根据 getter 方法反推出属性名,造成转为 JSON 字符串时和实际属性名存在偏差。
解决办法
遵循阿里巴巴 Java 开发手册
孤尽老师的《Java 开发手册》 中专门强调任何布尔类型的变量都不要加 is 前缀,基本类型布尔属性反向解析时,会误以为不带 is 导致获取不到属性,抛出异常。关注公众号:Java核心技术,回复:手册,可获取高清完整版。
使用别名
使用 fastjson 自带的 @JSONField 注解,不过这种方式 fastjson 的侵入性太强。
public class MyClass {
@JSONField( name="isActive")
// boolean 类型的属性
private boolean isActive;
private boolean valid;
// 省略其他
}
总结
我认为 对于 Java 程序员而言,《阿里巴巴 Java 开发手册》至少读 3 遍。 工作中发现太多常见低级问题都是 《阿里巴巴 Java 开发手册》已经存在的问题。关注公众号:Java核心技术,回复:手册,可获取高清完整版。
然而推荐很多次《阿里巴巴 Java 开发手册》虽然很薄,但是很多人还是不会认真阅读几遍,导致在相同的地方跌倒很多遍。哪怕遇到类似的问题,也很容易快速想出原因。
我们遇到问题时,一定不要止步于解决问题,而是应该寻找最合理的解决方案。比如虽然加上 @JSONField
可以“解决问题”,但侵入性太强,假如其他人也用这个对象使用其他 JSON 序列化工具,就会出问题,这并不是一个好的方案。
AI 时代,遇到问题自己如果不能快速解决时,可以考虑寻求 AI 的帮助。不过使用 AI 时一定要将问题交代清楚。很多同学说的问题连其他同事都听不懂,更不别说 AI 了。
版权声明:本文为CSDN博主「明明如月学长」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。原文链接:https://blog.csdn.net/w605283073/article/details/131270338
近期热文推荐:
1.1,000+ 道 Java面试题及答案整理(2022最新版)
2.劲爆!Java 协程要来了。。。
3.Spring Boot 2.x 教程,太全了!
4.别再写满屏的爆爆爆炸类了,试试装饰器模式,这才是优雅的方式!!
5.《Java开发手册(嵩山版)》最新发布,速速下载!
觉得不错,别忘了随手点赞+转发哦!
服务器租用托管,机房租用托管,主机租用托管,https://www.e1idc.com