zoukankan      html  css  js  c++  java
  • Java中的Json序列化,不容忽视的getter

    在开发的过程中,经常会碰到和自己预期不一样的情况。有的时候自己去研究一下还是很有趣的。这两天在写java web的时候,碰到了一个对象序列化的问题。

    问题重现

    public class AjaxJson {
        private boolean success;
        private String msg;
        private Object obj;
        private Map<String, Object> attributes;
        
        //getter and setter
    
        public String getJsonStr() {
            JSONObject obj = new JSONObject();
            obj.put("success", this.isSuccess());
            obj.put("msg", this.getMsg());
            obj.put("obj", this.obj);
            obj.put("attributes", this.attributes);
            return obj.toJSONString();
        }
    }
    

    上面是一个接口类,我们需要把这个类的对象序列化成json返回。那么在springmvc中,一般是这样操作的。

    @RequestMapping(params = "/get")
    @ResponseBody
    public AjaxJson del(HttpServletRequest request) {
        AjaxJson json = new AjaxJson();
        //省略业务操作
        return json;
    }
    

    默认的话,返回ResponseBody,对象会直接序列化成json。这个时候,我们可以看一下返回的json。

    {
        "success": "true",
        "Msg":"1",
        "obj":{
            ...
        },
        "attributes": null,
        "jsonStr":"{"success": "true","Msg":"1","obj":{...},"attributes": null,}"
    }
    

    显然,和我们预期想的不太一样,多了一个jsonstr字段。这个时候我在想,是不是springmvc的问题。结果仔细一想,springnvc之所以可以直接将对象序列化成json,其实是我们添加的配置文件在起作用,真正参与序列化工作的是jackson这个库。于是,我单独使用了jackson,结果返回的json字符串和之前是相同的,这下就可以肯定是,jackson这个库本身的设计问题了。

    深入探讨

    带着这份好奇,我把java中常用的json序列化的库都试了一下,看看是否都是这样。主流的库有jackson、fastjson和gson。

    经过测试发现,jackson和阿里的fastjson返回的json字符串都带有一个jsonstr字段,唯独google的gson返回了我们预期的结果——只序列化对象的field。

    于是我找了下这几个库的序列化原理:

    • jackson和fastjson
      在序列化的时候,先利用反射找到对象类的所有get方法,接下来去get,然后小写化,作为json的每个key值,而get方法的返回值作为value。接下来再反射field,添加到json中。
    • gson
      没有找到通俗的讲法,不过感觉应该就和getter方法无关吧。

    所以,可以看大我们的AjaxJson类中存在这样一个getJsonStr,因此,jsonStr就作为key,序列化到json中了。

    当然在jackson中,提供了相应的annotation,可以把这类方法忽略掉。在方法前加上**@JsonIgnore **即可。

    个人理解

    • 遇到问题的时候,千万不要忽略一些简单的地方,例如getter和setter方法。用getXXX的地方,可以用fetch等替代。
    • 有时我们会在类中定义例如private int mAge的变量,而getter的方法是getAge()。显然我们希望在序列化的时候得到的key为age而非mAge,那么反射getter方法也就有它存在的意义了。

    参考文献

  • 相关阅读:
    Cisco ASR1002-X告警处理
    WLC5520无法通过无线客户端进行网管故障解决
    一键分享mob,方法二
    Java中堆内存和栈内存详解
    linux.linuxidc.com
    android中shape的使用(android:angle小解)
    Activity的Launch mode详解 :standard(默认), singleTop, singleTask和 singleInstance
    Android studio个人常用快捷键
    Android 公告新闻消息资讯之垂直滚动效果
    数据库设计相关
  • 原文地址:https://www.cnblogs.com/Sinte-Beuve/p/7270782.html
Copyright © 2011-2022 走看看