快看这个码农,他用fastjson2踩坑了

363 阅读2分钟

fastjson2踩坑实例

前言

最近看别人都疯狂的刷fastjson2,然后又是阿里的,搞得笔者也兴致勃勃的了解一下(话说也没有了解直接拿来写业务代码),然后就有巨坑在里面。希望大家看到了引以为戒,有什么更好的建议也可以一起讨论下。

环境

  1. jdk17
  2. 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不会通过,还是为了说清楚这个问题希望能引起大佬们的关注,很开心他们也关注到了这一个问题pr1pr2有上面的详情,大家可以看看.
其实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已经出现很多事故了,被公司大佬吊着锤,天天徘徊在被公司赶走的路上。最后感谢各位。