[alibaba/fastjson]父类中get方法返回值是Object,子类重写后返回String,有时会导致WriteNullStringAsEmpty功能不生效

2024-09-20 608 views
7

image 在TypeUtils的computeGetters方法中 image 这里的clazz.getMethods(),不能保证子类的get方法在父类的get方法之后,就可能导致父类的get方法覆盖子类的get方法,使字段信息中获取到的字段类型为Object,导致WriteNullStringAsEmpty不能生效。

回答

1
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.serializer.SerializerFeature;
import org.junit.Test;

public class Issue3655 {
    @Test
    public void test1() {
        B b = new B(null);
        System.out.println(JSON.toJSONString(b, SerializerFeature.WriteNullListAsEmpty));
    }

    public static abstract class A {
        public abstract Object getData();
    }

    public static class B extends A {
        private String data;

        public B(String data) {
            this.data = data;
        }

        public String getData() {
            return this.data;
        }

        public void setData(String data) {
            this.data = data;
        }
    }
}

1.2.75 存在此问题

3

使用 SerializerFeature.WriteNullStringAsEmpty

1

@wenshao 这个问题关闭掉,是不解决吗?

9

我之前发的TestCase确实是错误的,写成WriteNullListsAsEmpty了. 但是问题还是存在

package com.alibaba.json.bvt.issue_3600;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.serializer.SerializerFeature;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.Setter;
import org.junit.Assert;
import org.junit.Test;

public class Issue3655 {
    @Test
    public void test1() {
        issue3655_b b = new issue3655_b(null, null, null, null, null, null, null, null, null);
        String left = JSON.toJSONString(b, SerializerFeature.WriteNullStringAsEmpty);
        System.out.println(left);
        Assert.assertEquals(
                "{\"data\":\"\",\"data2\":\"\",\"data3\":\"\",\"data4\":\"\",\"data5\":\"\",\"data6\":\"\",\"data7\":\"\",\"data8\":\"\",\"data9\":\"\"}", left);
    }

    @Test
    public void test2() {
        issue3655_c c = new issue3655_c(null, null, null, null, null, null, null, null, null);
        String left = JSON.toJSONString(c, SerializerFeature.WriteNullStringAsEmpty);
        System.out.println(left);
        Assert.assertEquals(
                "{\"data\":\"\",\"data2\":\"\",\"data3\":\"\",\"data4\":\"\",\"data5\":\"\",\"data6\":\"\",\"data7\":\"\",\"data8\":\"\",\"data9\":\"\"}", left);
    }

    public static class issue3655_b extends issue3655_a {
        private String data;
        private String data2;
        private String data3;
        private String data4;
        private String data5;
        private String data6;
        private String data7;
        private String data8;
        private String data9;
        public String getData()  {return data;}
        public String getData2() {return data2;}
        public String getData3() {return data3;}
        public String getData4() {return data4;}
        public String getData5() {return data5;}
        public String getData6() {return data6;}
        public String getData7() {return data7;}
        public String getData8() {return data8;}
        public String getData9() {return data9;}
        public void setData(String data) {this.data = data;}
        public void setData2(String data) {this.data2 = data2;}
        public void setData3(String data) {this.data3 = data3;}
        public void setData4(String data) {this.data4 = data4;}
        public void setData5(String data) {this.data5 = data5;}
        public void setData6(String data) {this.data6 = data6;}
        public void setData7(String data) {this.data7 = data7;}
        public void setData8(String data) {this.data8 = data8;}
        public void setData9(String data) {this.data9 = data9;}

        public issue3655_b(
                String data, String data2, String data3, String data4, String data5,
                String data6, String data7, String data8, String data9) {
            this.data = data;
            this.data2 = data2;
            this.data3 = data3;
            this.data4 = data4;
            this.data5 = data5;
            this.data6 = data6;
            this.data7 = data7;
            this.data8 = data8;
            this.data9 = data9;
        }
    }

    @Getter
    @Setter
    @AllArgsConstructor
    public static class issue3655_c extends issue3655_a {
        private String data;
        private String data2;
        private String data3;
        private String data4;
        private String data5;
        private String data6;
        private String data7;
        private String data8;
        private String data9;
    }

    public static abstract class issue3655_a {
        public abstract Object getData();
        public abstract Object getData2();
        public abstract Object getData3();
        public abstract Object getData4();
        public abstract Object getData5();
        public abstract Object getData6();
        public abstract Object getData7();
        public abstract Object getData8();
        public abstract Object getData9();
    }

}

重复几次testcase可以发现,基本上每次的输出都不同,并且testcase大概率不通过.

比如输出:

org.junit.ComparisonFailure: 
预期:{"data":"","data2":"","data3":"","data4":"","data5":"","data6":"","data7":"","data8":"","data9":""}
实际:{"data":"","data3":"","data4":"","data5":""}

问题就出在那个clazz.getMethods(),getMethods()不保证顺序- 在一般实现里就是地址顺序. 因为Object自带10+方法,所以只有一个字段的对象,带上字段的getter,setter也就十几个方法,子类的get方法在父类的get方法之后概率还挺高,一旦字段多起来概率就下去了.

4

@wenshao