JSON(JavaScript Object Notation)是一种轻量级的数据交换格式.简洁和清晰的层次结构使得 JSON 成为理想的数据交换语言。 易于人阅读和编写,同时也易于机器解析和生成,并有效地提升网络传输效率。

1.1 JSON 语法规则

JSON是一个标记符的序列。这套标记符包含六个构造字符、字符串、数字和三个字面名。 JSON是一个序列化的对象或数组。

  • 六个构造字符:
  • begin-array [ 左方括号
  • begin-object { 左大括号
  • end-array ] 右方括号
  • end-object } 右大括号
  • name-separator : 冒号
  • value-separator , 逗号
  • 在这六个构造字符的前或后允许存在无意义的空白符: 空格、回车换行(\n),换页(\f),制表符(\t),回车(\r)
  • JSON的值:
  • 可以是对象、数组、数字、字符串或者三个字面值(false、null、true)中的一个。值中的字面值中的英文必须使用小写。
  • 对象由花括号括起来的逗号分割的成员构成,成员是字符串为key的键值对组成,键值对之间由逗号分隔
  • 数组是由方括号括起来的一组值构成
  • 字符串与C或者Java的字符串非常相似。字符串是由双引号包围的任意数量Unicode字符的集合,使用反斜线转义。一个字符(character)即一个单独的字符串(character string)。
  • 数字也与C或者Java的数值非常相似。除去未曾使用的八进制与十六进制格式。除去一些编码细节。
  • 语法规则,是解析和生成的主要依据,Gson库在JsonReader类依据此来解析数据的,在JsonWriter中依据这个来写数据的

    1.2 Gson库

    是Google公司发布的一个开放源代码的Java库,主要用途为序列化Java对象为JSON字符串,或反序列化JSON字符串成Java对象;主要有以下概念,这些概念与gson格式特点对应

  • Serialization:序列化,使Java对象到Json字符串的过程。
  • Deserialization:反序列化,字符串转换成Java对象。
  • JSON数据中的JsonElement有下面这四种类型:
  • JsonPrimitive: 例如一个字符串或整型
  • JsonObject: 以JsonElement为键值对集合。key值为string类型
  • JsonArray: JsonElement 的集合。注意数组的元素可以是四种类型中的任意一种,或者混合类型都支持。
  • JsonNull: 值为null
  • dependencies {
        implementation 'com.google.code.gson:gson:x.x.x'
    
    // 使用new方法
    Gson gson = new Gson();
    // toJson 将bean对象转换为json字符串
    String jsonStr = gson.toJson(user, Xxx.class);
    // fromJson 将json字符串转为bean对象
    Student user= gson.fromJson(jsonStr, Xxx.class);
    

    2、Gson源码分析

    这是一个序列化、反序列化json格式数据的库;它可以分为

  • json数据、键值对(值)的转换
  • class 和 键值对 转换、 集合数据和值转换
  • 整体过程封装代理
  • 2.1 整体架构

    java对象到json数据

    java对象通过TypeAdapter适配器写到JsonWriter中,JsonWriter负责具体的格式书写

    json数据到java对象 json数据通过进行包装,具体由JsonReader执行识别操作,通过TypeAdapter适配生成类对象

    TypeAdapter类 适配器作用,类和json解析出数据的桥梁;其中包括对象生成,成员变量解析、赋值

    JsonWriter 负责json格式字符串生成

    JsonReader 负责json格式字符串,解析成键值对或者单个值

    从代码角度来说使用了适配器模式,这个是核心模式;而其中又参杂了建造者模式、静态代理模式、策略模式、抽象工程模式等;有兴趣的可以具体去找找这些模式

    2.2 JsonReader

    按照json格式规则进行读取

  • 数组、集合,每次读取的都是单个元素
  • 开始读取: beginArray,并略过[
  • 读取: nextXXX系列,xxx基本类型;其它类型可以是array(按照1继续),也可以对象或者map(按照2继续)
  • 结束读取: endArray, 并略过]
  • map、对象按照元素键值对来读取
  • 开始读取: beginObject ,并略过{
  • 首先读取key: nextName
  • 然后读取: nextXXX系列,xxx基本类型;其它类型可以是array(按照1继续),也可以对象或者map(按照2继续)
  • 结束读取: endObject,并略过}
  • 其它一些方法,比如略过标记符、空白符等

    2.3 JsonWriter

    按照json格式规则进行写入

  • 数组、集合,每次写入的都是单个元素
  • 开始写入: beginArray,并写入[
  • 写入: valueXXX系列,xxx基本类型;其它类型可以是array(按照1继续),也可以对象或者map(按照2继续)
  • 结束写入: endArray, 并写入]
  • map、对象按照元素键值对来写入
  • 开始写入: beginObject, 并写入{
  • 首先准备key: name
  • 然后写入: valueXXX系列,xxx基本类型;其它类型可以是array(按照1继续),也可以对象或者map(按照2继续)
  • 结束写入: endObject,并写入}
  • 还有一些按照数据类别写入标记符,空白符

    2.4 TypeAdapter

    抽象类,其内部方法fromJson、toJson等方法通过read、write抽象方法来实现

    public abstract void write(JsonWriter out, T value) throws IOException;
    public abstract T read(JsonReader in) throws IOException;
    

    这两个方法实现了具体类型的读取写入过程

    这个可以分为以下几种

  • TypeAdapters中定义的单个元素类型,包括基本类型、Enum、特殊的基本类型、日期、网络等相关类
  • map类型,由工厂类MapTypeAdapterFactory来创建
  • 集合或者数组,由工厂类CollectionTypeAdapterFactory来创建
  • 用户定义的java bean类,由工厂类ReflectiveTypeAdapterFactory来创建
  • 注解? 由工厂类JsonAdapterAnnotationTypeAdapterFactory来创建,其内部由其它工厂来区分创建
  • 在这里,我们就分析下前四种,后面一种,由于没有用过,不是清楚什么类型,理解起来有点难度;

    2.4.1 TypeAdapters中的‘基本类型’

    这些是单值类型,作为数组或者集合的元素;也可以作为map或者java bean中的value类型,如果是字符串类型,也可以作为key类型

    Class类型,json数据不接受;read,write实现直接报异常

        public static final TypeAdapter<Class> CLASS = new TypeAdapter<Class>() {
        @Override
        public void write(JsonWriter out, Class value) throws IOException {
          throw new UnsupportedOperationException("Attempted to serialize java.lang.Class: "
                  + value.getName() + ". Forgot to register a type adapter?");
        @Override
        public Class read(JsonReader in) throws IOException {
          throw new UnsupportedOperationException(
                  "Attempted to deserialize a java.lang.Class. Forgot to register a type adapter?");
      }.nullSafe();
    

    String类型,代码就是把字符串读出,写入

    public static final TypeAdapter<StringBuilder> STRING_BUILDER = new TypeAdapter<StringBuilder>() {
        @Override
        public StringBuilder read(JsonReader in) throws IOException {
          if (in.peek() == JsonToken.NULL) {
            in.nextNull();
            return null;
          return new StringBuilder(in.nextString());
        @Override
        public void write(JsonWriter out, StringBuilder value) throws IOException {
          out.value(value == null ? null : value.toString());
    

    URL数据,写入时,写的是String,读取时也是String,不过再加了转换

        public static final TypeAdapter<URL> URL = new TypeAdapter<URL>() {
        @Override
        public URL read(JsonReader in) throws IOException {
          if (in.peek() == JsonToken.NULL) {
            in.nextNull();
            return null;
          String nextString = in.nextString();
          return "null".equals(nextString) ? null : new URL(nextString);
        @Override
        public void write(JsonWriter out, URL value) throws IOException {
          out.value(value == null ? null : value.toExternalForm());
    

    其它也有一些,都是通过转化成基本数据或者string类型来读取和写入的;

    2.4.2 map类型

    代码在MapTypeAdapterFactory中,比较多,就不列出来了,大致流程:

  • 通过反射获取key、value类型
  • 获取key、value对应的TypeAdapter
  • 通过各自的adapter进行读写
  • 源码中发现,其读取标签可以是{,[;也就是说这两中都是有效的

    2.4.3 java bean类型

    代码在ReflectiveTypeAdapterFactory中,比较多,就不列出来了,大致流程:

  • 初始化TypeAdapter时,首先得到成员变量名字、值信息集合,并对field进行打开隐私可见
  • 名字是string对应的TypeAdapter、value通过类型获取对应的TypeAdapter
  • 按照各自的TypeAdapter,按照key-value进行读写
  • 2.4.4 集合、数组类型

    代码在CollectionTypeAdapterFactory中,比较多,就不列出来了,大致流程

  • 获取元素对应的TypeAdapter
  • 通过元素的TypeAdapter进行读写
  • 2.5 惊喜小发现

    ObjectConstructor接口 数组、集合、map、普通类生成实例的

    Excluder:成员变量是否被序列化,反序列化

    FieldNamingStrategy 成员变量名字处理,不包括注解的名字

    LongSerializationPolicy,序列化值类

    文章中对具体TypeAdatpter并没有进行详细的代码流程分析;JsonReader,JsonWriter也没有进行详细的代码流程分析;这是因为,对于框架或者库的理解,首先要理解流程和原理,然后才是细节的处理;作者在这里只想作为进入Gson的辅助文章;更多的细节内容是硬知识,需要自己花费功夫去理解和记忆。

    技术变化都很快,但基础技术、理论知识永远都是那些;作者希望在余后的生活中,对常用技术点进行基础知识分享;如果你觉得文章写的不错,请给与关注和点赞;如果文章存在错误,也请多多指教!

    众少成多积小致巨
    粉丝