alibaba / fastjson2

🚄 FASTJSON2 is a Java JSON library with excellent performance.
Apache License 2.0
3.78k stars 495 forks source link

[BUG]对于对象中包含aBcd格式的字段,并且字段是私有的,提供get方法访问,生成json时会把aBcd字段变成ABcd,序列化不符合预期 #2932

Closed werson closed 1 month ago

werson commented 2 months ago

问题描述

简要描述您碰到的问题。 JSON.toJSONString

public static void main(String[] args) { ATestClass vo = ATestClass.builder().rMepId(2).build(); System.out.println(com.alibaba.fastjson2.JSON.toJSONString(vo)); }

image image

环境信息

请填写以下信息:

重现步骤

如何操作可以重现该问题:

  1. 使用 xxx.xxx 方法
  2. 输入 ... 数据
  3. 出现 ... 错误
    //可在此输入示例代码

期待的正确结果

对您期望发生的结果进行清晰简洁的描述。

相关日志输出

请复制并粘贴任何相关的日志输出。

附加信息

如果你还有其他需要提供的信息,可以在这里填写(可以提供截图、视频等)。

werson commented 2 months ago

同issue https://github.com/alibaba/fastjson2/issues/2825 JSONFactory.getDefaultObjectWriterProvider().setNamingStrategy(PropertyNamingStrategy.CamelCase1x)

CodePlayer commented 1 month ago

这其实不算 bug,因为 Java Bean 规范就是这么规定的。

对象的规范属性名称,不是根据 private 的 字段名称来确定的,而是根据 public 的 getter 方法的名称来确定的。 如果你的 getter 方法名为 getABcd(),去掉 get 前缀就是 "ABcd"。 根据 JavaBean 规范,如果第二个字母是大写的,第一个就不需要转为小写。比如 getCPU(),解析出来的属性名称就是 CPU。 同理,getABcd() 解析出来就是 ABcd

你可以参考 JDK 自带的 java.beans.Introspector.decapitalize("ABcd") 方法的输出结果及源代码:

    /**
     * Utility method to take a string and convert it to normal Java variable
     * name capitalization.  This normally means converting the first
     * character from upper case to lower case, but in the (unusual) special
     * case when there is more than one character and both the first and
     * second characters are upper case, we leave it alone.
     * <p>
     * Thus "FooBah" becomes "fooBah" and "X" becomes "x", but "URL" stays
     * as "URL".
     *
     * @param  name The string to be decapitalized.
     * @return  The decapitalized version of the string.
     */
    public static String decapitalize(String name) {
        if (name == null || name.length() == 0) {
            return name;
        }
        if (name.length() > 1 && Character.isUpperCase(name.charAt(1)) &&
                        Character.isUpperCase(name.charAt(0))){
            return name;
        }
        char[] chars = name.toCharArray();
        chars[0] = Character.toLowerCase(chars[0]);
        return new String(chars);
    }

如果您就是想保持属性名称为原始的字段名称,即"aBcd",那么可以用以下任一办法解决:

  1. 将 getter 方法改为 getaBcd()
  2. 自定义注解 @JSONField(name = "aBcd") (定义为任意有效名称都可以)。
  3. 使用 JSONWriter.Feature.FieldBased 来强制忽略所有 getter,仅根据字段输出,例如:JSON.toJSONString(obj, JSONWriter.Feature.FieldBased)