记一次JSON.toJSONString()转换时非属性方法空指针异常排查及toJSONString保留null值属性

记一次JSON.toJSONString()转换时非属性方法空指针异常排查及toJSONString保留null值属性

在这里插入图片描述

异常详情

有一个类,里面有两个属性和一个类似工具的getRealName()方法如下:

getRealName()方法就是获取这个人的真实名字,如果获取不到就以name返回

class JSONTest {
        String name;
        String age;

        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }

        public String getAge() {
            return age;
        }

        public void setAge(String age) {
            this.age = age;
        }

        public String getRealName() {
            try {
                return "real" + this.name.substring(0, 1);
            } catch (Exception e) {
                e.printStackTrace();
            }
            return this.name;
        }
    }

然后Controller中有两个url使用了这个类,并转成JSONString返回。下面就以两个方法模仿这两个url。

public class JsonMainTest {
    public static void main(String[] args) throws Exception {
        System.out.println(method01());
        System.out.println(method02());
    }

    static String method01() {
        JSONTest jsonTest = new JSONTest();
        jsonTest.setName("lowkey");
        jsonTest.setAge("18");
        jsonTest.setName(jsonTest.getRealName());
        return JSON.toJSONString(jsonTest);
    }

    static String method02() {
        JSONTest jsonTest = new JSONTest();
        jsonTest.setAge("18");
        return JSON.toJSONString(jsonTest);
    }
}

接下来运行这个main方法,可以看到第二个方法报错了

在这里插入图片描述

异常原因

一开始很好奇为什么会异常,因为空指针,name为空了,但是我method02方法并没有调用getRealName(),为什么会调用了它,并空指针了呢。

后面细究发现是因为JSON.toJSONString()的时候是根据getter方法进行的,也就是下面这行
在这里插入图片描述

它会把所有符合以get开头的方法拿出来然后把它转成属性进行设置,所有他会在转method02方法的时候调用了getRealName()方法,而method02方法中name并没有设置值,所有才出现了空指针异常。在过程中还发现它会扫描以is开头的方法。

从打印的JSONString串也可以看出,我的属性里面并没有realName属性它却打印了出来。

解决方案

  • 第一种

    就是规范命名,与类属性无关的方法不要以get/is开头,向我这个类里面getRealName只是将name进行了处理,并不是作为一个类属性使用,所以我们将该方法改成handleRealName()或者其他即可。如下所示:再次运行便正常了,打印中也没有除属性外的字段。

    public class JsonMainTest {
        public static void main(String[] args) throws Exception {
            System.out.println(method01());
            System.out.println(method02());
        }
        static String method01() {
            JSONTest jsonTest = new JSONTest();
            jsonTest.setName("lowkey");
            jsonTest.setAge("18");
            jsonTest.setName(jsonTest.handletRealName());
            return JSON.toJSONString(jsonTest);
        }
        static String method02() {
            JSONTest jsonTest = new JSONTest();
            jsonTest.setAge("18");
            return JSON.toJSONString(jsonTest);
        }
    }
    
    class JSONTest {
        String name;
        String age;
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public String getAge() {
            return age;
        }
    
        public void setAge(String age) {
            this.age = age;
        }
    
        public String handletRealName() {
            try {
                return "real" + this.name.substring(0, 1);
            } catch (Exception e) {
                e.printStackTrace();
            }
            return this.name;
        }
    }
    
  • 第二种

    忽略JSON转换,即在进行JSON.toJSONString的时候忽略getRealName方法。在方法上添加@JSONField(serialize = false)注解,如下所示:

    public class JsonMainTest {
        public static void main(String[] args) throws Exception {
            System.out.println(method01());
            System.out.println(method02());
        }
    
        static String method01() {
            JSONTest jsonTest = new JSONTest();
            jsonTest.setName("lowkey");
            jsonTest.setAge("18");
            jsonTest.setName(jsonTest.getRealName());
            return JSON.toJSONString(jsonTest);
        }
    
        static String method02() {
            JSONTest jsonTest = new JSONTest();
            jsonTest.setAge("18");
            return JSON.toJSONString(jsonTest);
        }
    }
    
    class JSONTest {
        String name;
        String age;
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public String getAge() {
            return age;
        }
    
        public void setAge(String age) {
            this.age = age;
        }
    
        @JSONField(serialize = false)
        public String getRealName() {
            try {
                return "real" + this.name.substring(0, 1);
            } catch (Exception e) {
                e.printStackTrace();
            }
            return this.name;
        }
    }
    
  • 不过建议还是规范命名

其他问题:空属性不打印的情况

我们还会发现为空的属性,toJSONStirng的时候不打印。我们可以使用时添加SerializerFeature.WriteMapNullValue属性:

JSON.toJSONString(jsonTest, SerializerFeature.WriteMapNullValue);
  • 5
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

低调D树苗

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值