fastjson2踩坑实例
前言
最近看别人都疯狂的刷fastjson2,然后又是阿里的,搞得笔者也兴致勃勃的了解一下(话说也没有了解直接拿来写业务代码),然后就有巨坑在里面。希望大家看到了引以为戒,有什么更好的建议也可以一起讨论下。
环境
- jdk17
- fastjson2.0.8
问题1
@Data
public class B {
private String cId;
}
public static void main(String[] args) {
B object = new B();
object.setCId("1");
System.out.println(JSON.toJSONString(object));
//按道理{"cId":"1"}
//结果{"CId":"1"}
}
根据以上代码,其实跟项目贡献成员有讨论过,笔者也暴力直接提交垃圾代码上去审核,但是深知这个pr不会通过,还是为了说清楚这个问题希望能引起大佬们的关注,很开心他们也关注到了这一个问题pr1和pr2有上面的详情,大家可以看看.
其实fastjson2拿值的时候是通过模仿java的Introspector去拿到javabean信息,通过方法名字获取到fieldName再进行下一次操作,而对于cId,uId,他们的get方法为**getUId()**而去掉get剩下UId后通过模仿内省获取到的名字就是UId所以导致fieldName为UId,最后解析出来的jsonKey就是UId
public abstract class BeanUtils {
public static String getterName(String methodName, String namingStrategy) {
if (namingStrategy == null) {
namingStrategy = "CamelCase";
}
final int methodNameLength = methodName.length();
boolean is = methodName.startsWith("is");
boolean get = methodName.startsWith("get");
final int prefixLength;
if (is) {
prefixLength = 2;
} else if (get) {
prefixLength = 3;
} else {
prefixLength = 0;
}
switch (namingStrategy) {
case "NeverUseThisValueExceptDefaultValue":
case "CamelCase": {
char[] chars = new char[methodNameLength - prefixLength];
methodName.getChars(prefixLength, methodNameLength, chars, 0);
char c0 = chars[0];
if (c0 >= 'A' && c0 <= 'Z') {
chars[0] = (char) (c0 + 32);
}
return new String(chars);
}
case "PascalCase": {
return pascal(methodName, methodNameLength, prefixLength);
}
case "SnakeCase": {
return snakeCase(methodName, prefixLength);
}
case "UpperCaseWithUnderScores": {
return underScores(methodName, prefixLength, true);
}
case "UpperCamelCaseWithSpaces":
return upperCamelWith(methodName, prefixLength, ' ');
case "UpperCase":
return methodName.substring(prefixLength).toUpperCase();
case "UpperCaseWithDashes":
return dashes(methodName, prefixLength, true);
case "UpperCaseWithDots":
return dots(methodName, prefixLength, true);
case "KebabCase": {
StringBuilder buf = new StringBuilder();
final int firstIndex;
if (is) {
firstIndex = 2;
} else if (get) {
firstIndex = 3;
} else {
firstIndex = 0;
}
for (int i = firstIndex; i < methodName.length(); ++i) {
char ch = methodName.charAt(i);
if (ch >= 'A' && ch <= 'Z') {
char chUcase = (char) (ch + 32);
if (i > firstIndex) {
buf.append('-');
}
buf.append(chUcase);
} else {
buf.append(ch);
}
}
return buf.toString();
}
default:
throw new JSONException("TODO : " + namingStrategy);
}
}
}
问题2
用惯了fastjson v1的想着直接加@JSONField(name = "cId")就好了对吧!?,那就大错特错了
@Data
public class B {
@JSONField(name = "cId")
private String cId;
}
public static void main(String[] args) {
B object = new B();
object.setCId("1");
System.out.println(JSON.toJSONString(object));
//按道理{"cId":"1"}
//结果{"CId":"1"}
}
为什么结果依然是没变的呢???? 那就涉及到了另外一行坑代码
BeanUtils.declaredFields(objectClass, field -> {
if (field.getName().equals(fieldName)) {
int modifiers = field.getModifiers();
if ((!Modifier.isPublic(modifiers)) && !Modifier.isStatic(modifiers)) {
getFieldInfo(beanInfo, fieldInfo, objectClass, field);
}
}
});
这里的field.getName = cId而fieldName为CId,那么这样肯定就进不去getFieldInfo这个方法里面,所以导致JSONField没有生效
总结
使用fastjson2,最好就熟悉下JavaBean,Java内省之类的,然后属性定义最后也不要uId、cId之类的可以这样
@Data
public class B {
@JSONField(name = "cId")
private String clientId;
}
而且新出的任何工具,没有经过风吹雨打千万不要上生产,笔者因为使用jdk17已经出现很多事故了,被公司大佬吊着锤,天天徘徊在被公司赶走的路上。最后感谢各位。