fastjson源码解析——反序列化(四)

2021SC@SDUSC

本文在CSDN个人博客同步发出,地址CSDN博客

概要

经过前5篇的介绍,相信大家已经对于单一对象的反序列化实现有了一个较详细的认知。接下来,回到我们的任务parseArray()方法,从反序列化为数组的过程中,继续学习反序列化的逻辑。本文作为数组反序列化的第一篇,会重点介绍parseArray()API的几种调用方式。

parseArray()的重要性

在现代软件开发的过程中,对于数据的传输,已经不可能只局限于将数据存放在一个对象里,必然需要传输一组相同的数据结构(e.g. 同一个类的对象)。这类情况,这些数据结构绝大多数都存放在数组内,这就对数组的序列化、反序列化有着非常大的刚性需求。
举个例子,在数据库课设中,每一班火车都是一个独立的对象,在HTTP/HTTPS协议上传输,根本不可能维持一个稳定长时间的连接,只可能是Browser端发送请求时,HTTP的Server端才可以向B端发送数据。如果没有对数组的序列化、反序列化,那么每个请求都只能传输一个对象(toJSONString(),parseObject()),无法及时显示所有的火车班次信息。由此可见,对于对象数组的序列、反序列化操作至关重要。

下面,使用idea作为IDE,编写demo,添加合适的断点,开始对com.alibaba.fastjson.JSON.parseArray()的几个重载API进行分析。

正式开始

我们先从最简单的API开始,逐渐尝试对反序列化进行配置

1. List<T> parseArray(String text, Class<T> clazz)

此API被最多人所使用,只需要传入JSONString和需要反序列化的类Clazz即可实现对json字符串的数组反序列化操作,不需要其他的配置。
看看调用API的代码:

    public static void main(String[] args) {
        Person[] people=new Person[3];
        people[0]=new Person(1,"Sam","Sam's des");
        people[1]=new Person(2,"John","John's des");
        people[2]=new Person(3,"Lily","Lily's des");

        String JSONString=JSON.toJSONString(people);
        System.out.println(JSONString);
        List<Person> testDeserialize=JSON.parseArray(JSONString,Person.class);
    }

程序先使用fastjson的序列化API,将Person[]类型序列化,形成json字符串。再调用我们研究目标parseArray(String,Class<T>)将json字符串反序列化生成数组。
使用断点+debug的方法,能看到运行过程:
debug过程
由此可以看出,fastjson生成的字符串与设想的并无差别,反序列化的parseArray(String,Class<T>)也生成了所需的List<T>对象,存储了3个Person对象。
这个API的介绍就到此为止,我们可以再次发现,fastjson所提供的API都非常简单,但是这些API却可以满足绝大多数开发者对json发送、解析的需要。

简介的接口调用方式,易于学习一直是fastjson,乃至alibaba开发的一个指导性思想。fastjson的API其实对大部分开发者,只需要使用toJSONString(Object),parseObject(String,Class<T>),parseArray(String,Class<T>)这三个。
这样简单的API,也助力fastjson的普及。正是凭借fastjson的高效、简洁,它自发布以来一直蝉联json解析器benchmark第一名。更少的API意味着对功能更完全的封装,对API调用者的便利,也让开发显得更自然、简单,接近人的思维。
对于未来的学习、开发而言,我们的代码也应该尽可能实现API的提质减量,让尽可能少的API实现

2. List<Object> parseArray(String text, Type[] types)

这个API解决了上一个API未解决的问题,即可能存在类间关系(extends, implements, etc..)或其他导致一个json字符串包含了几种不同类的情况。这时为了正确地实现反序列化,需要向解析器传入类型数组Type[],告知每个位置的类型信息,让fastjson按照types的顺序实现每一个对象的反序列化。
API调用demo

//main方法
    public static void main(String[] args) {
        Person[] people=new Person[3];
        people[0]=new Person(1,"Sam","Sam's des");
        people[1]=new Person(2,"John","John's des");
        people[2]=new Student(3,"Lily","Lily's des");//第3个人变成学生对象

        String JSONString=JSON.toJSONString(people);
        System.out.println(JSONString);
        Type[] types=new Type[3];
        types[0]=people[0].getClass();
        types[1]=people[1].getClass();
        types[2]=people[2].getClass();
        List<Object> testDeserialize=JSON.parseArray(JSONString,types);
    }
//Student类,继承了Person类,多了一个成员变量type
public class Student extends Person{
    public Student(){
        super();
    }
    public Student(int id, String name, String description) {
        super(id, name, description);
    }
    private String type="student";
    public String getType() {return type;}
    public void setType(String type) {this.type = type;}
}

demo的逻辑同上,先序列化,再传入Type[]数组,实现反序列化。
使用设置断点的方法,我们可以看到:
debug过程
图中已经标记出fastjson使用Type[]数组传入的类型,将Student.Lily成功反序列化成为Student类的对象,且可以看到,他的私有属性Type也成功反序列化。
需要注意的是,与上一个API不同,此API返回的类型不再是List<T>,而是List<Object>。这意味着他不仅仅支持将同一个超类的所有子类反序列化,而还可以将任意类型的对象反序列化,只需要在Type[]中标出他的类型即可。
此API调用方式依然简单,即便自由度很高,它的调用逻辑仍然符合正常人的思维。

更多

除以上2个API外,还存在需要配置的API,例如
JSONArray parseArray(String text, ParserConfig parserConfig)List<Object> parseArray(String text, Type[] types, ParserConfig config)。配置可以理解为根据自己的需要,设置fastjson反序列化过程中存在的各默认参数值(e.g. asm status)。但是上文提到的2个API已经覆盖95%以上的调用需要,需要配置的API多数用于很复杂的情况,因此不过多介绍。

最后

本文从parseObject的介绍,转向介绍parseArray()API的调用方式,从一个全新的角度来看反序列化的另外一个需求————对象数组的反序列化。正如我们开始parseObject()的分析一样,本文从API调用开始介绍。这部分API比parseObject复杂,但是仍然符合自然思维。
阿里巴巴的开发者编写的代码、API简洁,也提醒我们,尽可能简化API、程序代码,提高效率,提高可读性、易用性。下一期,我们将正式开始数组反序列化实现的探究。
感谢各位老师的阅读与指导!

发表评论