Gson中JsonReader的源码解析

JsonReader 的源码解析

JsonReader是用来反序列化Json字符串的主要类。

重点属性

stack: 一个int数组,默认32位

stackSize: 栈的长度

Peeked: 当前字符的状态 一共有17种状态

状态作用
PEEKED_NONE0
PEEKED_BEGIN_OBJECT1
PEEKED_END_OBJECT2
PEEKED_BEGIN_ARRAY3
PEEKED_END_ARRAY4
PEEKED_TRUE5
PEEKED_FALSE6
PEEKED_NULL7
PEEKED_SINGLE_QUOTED8
PEEKED_DOUBLE_QUOTED9
PEEKED_UNQUOTED10
PEEKED_BUFFERED11
PEEKED_SINGLE_QUOTED_NAME12
PEEKED_DOUBLE_QUOTED_NAME13
PEEKED_UNQUOTED_NAME14
PEEKED_NUMBER15
PEEKED_EOF16

JsonScope:8种状态,当前层级的状态peekStack

状态
EMPTY_ARRAY1
NONEMPTY_ARRAY2
EMPTY_OBJECT3
DANGLING_NAME4
NONEMPTY_OBJECT5
EMPTY_DOCUMENT6
NONEMPTY_DOCUMENT7
CLOSED8

重点方法:

  • doPeek()

这个方法是最重要的一个方法,该方法进行字符读取,并根据当前的层级状态peekStack来处理字符串,最后返回将要处理字符的状态Peeked。

我们需要知道Json是一个层级的树形,它是一层一层的,主要是通过[]{}来对数据进行层级的分层。

{
  stack[stackSize++] = JsonScope.EMPTY_DOCUMENT;
}
  int peeked = PEEKED_NONE;

首先,它在构造代码块中先将层级定位1层,此时代码的层级是1,代码层级的状态是EMPTY_DOCUMENT,peeked的初始状态是PEEKED_NONE。

我们以一个简单的例子,走一下,在此为了更好的理解,会交叉写一下其他的方法。

{"a": ["one"], "b": 123}

若要反序列化这个字符串,需要这样读。

 JsonReader reader = new JsonReader(reader(
        "{\"a\": [\"one\"], \"b\": 123}"));
 reader.beginObject();
 reader.nextName();
 reader.beginArray();
 reader.nextString();
 reader.endArray();
 reader.nextName();
 reader.nextInt();
 reader.endObject();

reader.beginObject()中会看到:

 public void beginObject() throws IOException {
    int p = peeked;
    if (p == PEEKED_NONE) {
      p = doPeek();
    }
   ...
  }

都会先走dopeek()方法,获取PeekStack,进行判断字符状态。

在这里插入图片描述

初始化时,PeekStack=EMPTY_DOCUMENT

else if (peekStack == JsonScope.EMPTY_DOCUMENT) {
  if (lenient) {
    consumeNonExecutePrefix();//这一步就是把前面无关的字符删除,比如空格,· 等不属于json的字符
  }
  stack[stackSize - 1] = JsonScope.NONEMPTY_DOCUMENT;
} 
//此时stack[NONEMPTY_DOCUMENT],StackSize=1

将当前层级的状态修改为了JsonScope.NONEMPTY_DOCUMENT。

 int c = nextNonWhitespace(true); //这个方法是读取下一个字符
    switch (c) {
    ...
    case '{':
      return peeked = PEEKED_BEGIN_OBJECT;
    default:
      pos--; // Don't consume the first character in a literal value.
    }

根据字符的ASCii码对相应的字符返回相应的字符状态,根据以上代码会返回 peeked = PEEKED_BEGIN_OBJECT。

接着看beginObject(),

if (p == PEEKED_BEGIN_OBJECT) {
  push(JsonScope.EMPTY_OBJECT);
  peeked = PEEKED_NONE;
} else {
  throw new IllegalStateException("Expected BEGIN_OBJECT but was " + peek() + locationString());
}

  private void push(int newTop) {
      ...
      stack[stackSize++] = newTop;
    }
//此时stack[NONEMPTY_DOCUMENT,EMPTY_OBJECT],StackSize =2;

当字符是PEEKED_BEGIN_OBJECT时,会在stack[]中添加新的层级EMPTY_OBJECT,StackSize+1。接着看nextName(),

 public String nextName() throws IOException {
    int p = peeked;
    if (p == PEEKED_NONE) {
      p = doPeek();
    }
  ...
  }

它也会走dopeek(),这时取到的PeekStack = PEEKED_BEGIN_OBJECT。

if (peekStack == JsonScope.EMPTY_OBJECT || peekStack == JsonScope.NONEMPTY_OBJECT) {
      stack[stackSize - 1] = JsonScope.DANGLING_NAME;
      // Look for a comma before the next element.
 			...
      int c = nextNonWhitespace(true);
      switch (c) {
      case '"':
        return peeked = PEEKED_DOUBLE_QUOTED_NAME;
     ...
      default:
      ...
      }
    }
//此时stack[NONEMPTY_DOCUMENT,DANGLING_NAME],StackSize =2;

将当前的层级状态改为DANGLING_NAME,并返回字符状态为PEEKED_DOUBLE_QUOTED_NAME,再看nextName()

   String result;
    if (p == PEEKED_UNQUOTED_NAME) {
      result = nextUnquotedValue();
    } else if (p == PEEKED_SINGLE_QUOTED_NAME) {
      result = nextQuotedValue('\'');
    } else if (p == PEEKED_DOUBLE_QUOTED_NAME) {
      result = nextQuotedValue('"'); 
    } else {
      throw new IllegalStateException("Expected a name but was " + peek() + locationString());
    }
    peeked = PEEKED_NONE;
    pathNames[stackSize - 1] = result;
    return result;

nextQuotedValue('"')会读取到""中的内容给result中,接着将peeked设置为PEEKED_NONE。到这里我们会发现PEEKED_NONE是新的字符开始读取和结束的状态。

接着 reader.beginArray();,beginArray()和beginObject()方法很像,我们走一下,还是先走doPeek()

if (peekStack == JsonScope.DANGLING_NAME) {
  stack[stackSize - 1] = JsonScope.NONEMPTY_OBJECT;
  // Look for a colon before the value.
  int c = nextNonWhitespace(true);
  switch (c) {
    case ':':
      break;
    case '=':
      checkLenient();
      if ((pos < limit || fillBuffer(1)) && buffer[pos] == '>') {
        pos++;
      }
      break;
    default:
      throw syntaxError("Expected ':'");
  }
}
//此时stack[NONEMPTY_DOCUMENT,NONEMPTY_OBJECT],StackSize =2;

此时的层级状态为DANGLING_NAME,会修改成NONEMPTY_OBJECT,在:处break,dopeek()接着往下走。

int c = nextNonWhitespace(true);//读取下一个字符
    switch (c) {
  		...
    case '[':
      return peeked = PEEKED_BEGIN_ARRAY;
      ...
    default:
      pos--; // Don't consume the first character in a literal value.
    }

会返回字符的状态PEEKED_BEGIN_ARRAY。 在看beginArray(),会在stack[]中再加一层,StackSize+1。

 //begainArray
if (p == PEEKED_BEGIN_ARRAY) {
      push(JsonScope.EMPTY_ARRAY);
      pathIndices[stackSize - 1] = 0;
      peeked = PEEKED_NONE;
    } else {
      throw new IllegalStateException("Expected BEGIN_ARRAY but was " + peek() + locationString() + ",v="+nextErrorString());
    }
//此时stack[NONEMPTY_DOCUMENT,NONEMPTY_OBJECT,EMPTY_ARRAY],StackSize =3

reader.nextString();仍然先走dopeek()

if (peekStack == JsonScope.EMPTY_ARRAY) {
  stack[stackSize - 1] = JsonScope.NONEMPTY_ARRAY;
}
 int c = nextNonWhitespace(true);
    switch (c) {
    case '"':
      return peeked = PEEKED_DOUBLE_QUOTED;
    default:
      pos--; // Don't consume the first character in a literal value.
    }
//此时stack[NONEMPTY_DOCUMENT,NONEMPTY_OBJECT,NONEMPTY_ARRAY],StackSize =3

然后在nextString()中将nextQuotedValue('"'),将双引号中的字符读取出来。字符状态恢复到PEEKED_NONE。

reader.endArray(); 仍然先走dopeek()

if (peekStack == JsonScope.NONEMPTY_ARRAY) {
  // Look for a comma before the next element.
  int c = nextNonWhitespace(true);
  switch (c) {
    case ']':
      return peeked = PEEKED_END_ARRAY;
    case ';':
      checkLenient(); // fall-through
    case ',':
      break;
    default:
      throw syntaxError("Unterminated array");
  }
} 

会返回字符状态PEEKED_END_ARRAY,看一下endArray().

if (p == PEEKED_END_ARRAY) {
  stackSize--;
  pathIndices[stackSize - 1]++; //为了记录路径使用的
  peeked = PEEKED_NONE;
} else {
  throw new IllegalStateException("Expected END_ARRAY but was " + peek() + locationString());
}
//此时stack[NONEMPTY_DOCUMENT,NONEMPTY_OBJECT],StackSize =2 

//实际上stack[NONEMPTY_DOCUMENT,NONEMPTY_OBJECT,NONEMPTY_ARRAY],但是NONEMPTY_ARRAY这个已经无关紧要了只是没有清0而已

reader.nextName();仍然先走doPeek().

if (peekStack == JsonScope.EMPTY_OBJECT || peekStack == JsonScope.NONEMPTY_OBJECT) {
      stack[stackSize - 1] = JsonScope.DANGLING_NAME;
      // Look for a comma before the next element.
      if (peekStack == JsonScope.NONEMPTY_OBJECT) {
        int c = nextNonWhitespace(true);
        switch (c) {
        ...
        case ',':
          break;
        ...
        }
      }
      int c = nextNonWhitespace(true);
      switch (c) {
      case '"':
        return peeked = PEEKED_DOUBLE_QUOTED_NAME;
        ...
      }
    }
//此时stack[NONEMPTY_DOCUMENT,DANGLING_NAME],StackSize =2 

返回字符状态PEEKED_DOUBLE_QUOTED_NAME,nextName()中,会读取字符串的值,并将字符移动到"的位置。

reader.nextInt(),仍然先走doPeek()

if (peekStack == JsonScope.DANGLING_NAME) {
      stack[stackSize - 1] = JsonScope.NONEMPTY_OBJECT;
      // Look for a colon before the value.
      int c = nextNonWhitespace(true);
      switch (c) {
      case ':':
        break;
      default:
        throw syntaxError("Expected ':'");
      }
    } 
result = peekNumber();
if (result != PEEKED_NONE) {
  return result;
}
//此时stack[NONEMPTY_DOCUMENT,NONEMPTY_OBJECT],StackSize =2 

peekNumber()方法会读取:后的数字,正常情路下主要返回PEEKED_LONG和PEEKED_NUMBER这两个状态,在nextInt()中去读取要读取的字符串。

reader.endObject(); 仍然走dopeek(),返回字符状态PEEKED_END_OBJECT。

if (peekStack == JsonScope.NONEMPTY_OBJECT) {
  int c = nextNonWhitespace(true);
  switch (c) {
    case '}':
      return peeked = PEEKED_END_OBJECT;
      ...
    default:
      throw syntaxError("Unterminated object");
  }
}

endObject()中会将stack[]进行更新。

 if (p == PEEKED_END_OBJECT) {
      stackSize--;
      pathNames[stackSize] = null; // Free the last path name so that it can be garbage collected!
      pathIndices[stackSize - 1]++;
      peeked = PEEKED_NONE;
    } else {
      throw new IllegalStateException("Expected END_OBJECT but was " + peek() + locationString());
    }
//此时stack[NONEMPTY_DOCUMENT],StackSize =1

到此整个上面代码的源码流程就走完了,因为走的是正常情况,中间的纠错没有细致来分析,但此时stack[]仍然是NONEMPTY_DOCUMENT,是不是就还可以继续往下走,可以用JsonReader#peek(),仍然走dopeek()

if (peekStack == JsonScope.NONEMPTY_DOCUMENT) {
  int c = nextNonWhitespace(false);
  if (c == -1) {
    return peeked = PEEKED_EOF;
  } else {
    checkLenient();
    pos--;
  }
}
//此时stack[NONEMPTY_DOCUMENT],StackSize =1 仍然不变

但是会返回字符状态PEEKED_EOF,这是结束的标志。

由以上的流程来总结一下doPeek()方法:

根据JsonCope来返回当前的字符状态,主要处理JsonCope的状态,读取下一个字符,判断当前字符的状态。

//第一个流程 能直接根据当前字符和JsonScope确定当前字符状态的
 if (peekStack == JsonScope.EMPTY_ARRAY) {
      stack[stackSize - 1] = JsonScope.NONEMPTY_ARRAY;
    } else if (peekStack == JsonScope.NONEMPTY_ARRAY) {
      // Look for a comma before the next element.
      int c = nextNonWhitespace(true);
      switch (c) {
      case ']':
        return peeked = PEEKED_END_ARRAY;
      case ';':
        checkLenient(); // fall-through
      case ',':
        break;
      default:
        throw syntaxError("Unterminated array");
      }
    } else if (peekStack == JsonScope.EMPTY_OBJECT || peekStack == JsonScope.NONEMPTY_OBJECT) {
      stack[stackSize - 1] = JsonScope.DANGLING_NAME;
      // Look for a comma before the next element.
      if (peekStack == JsonScope.NONEMPTY_OBJECT) {
        int c = nextNonWhitespace(true);
        switch (c) {
        case '}':
          return peeked = PEEKED_END_OBJECT;
        case ';':
          checkLenient(); // fall-through
        case ',':
          break;
        default:
          throw syntaxError("Unterminated object");
        }
      }
      int c = nextNonWhitespace(true);
      switch (c) {
      case '"':
        return peeked = PEEKED_DOUBLE_QUOTED_NAME;
      case '\'':
        checkLenient();
        return peeked = PEEKED_SINGLE_QUOTED_NAME;
      case '}':
        if (peekStack != JsonScope.NONEMPTY_OBJECT) {
          return peeked = PEEKED_END_OBJECT;
        } else {
          throw syntaxError("Expected name");
        }
      default:
        checkLenient();
        pos--; // Don't consume the first character in an unquoted string.
        if (isLiteral((char) c)) {
          return peeked = PEEKED_UNQUOTED_NAME;
        } else {
          throw syntaxError("Expected name");
        }
      }
    } else if (peekStack == JsonScope.DANGLING_NAME) {
      stack[stackSize - 1] = JsonScope.NONEMPTY_OBJECT;
      // Look for a colon before the value.
      int c = nextNonWhitespace(true);
      switch (c) {
      case ':':
        break;
      case '=':
        checkLenient();
        if ((pos < limit || fillBuffer(1)) && buffer[pos] == '>') {
          pos++;
        }
        break;
      default:
        throw syntaxError("Expected ':'");
      }
    } else if (peekStack == JsonScope.EMPTY_DOCUMENT) {
      if (lenient) {
        consumeNonExecutePrefix();
      }
      stack[stackSize - 1] = JsonScope.NONEMPTY_DOCUMENT;
    } else if (peekStack == JsonScope.NONEMPTY_DOCUMENT) {
      int c = nextNonWhitespace(false);
      if (c == -1) {
        return peeked = PEEKED_EOF;
      } else {
        checkLenient();
        pos--;
      }
    } else if (peekStack == JsonScope.CLOSED) {
      throw new IllegalStateException("JsonReader is closed");
    }
//第二步 消费下一个字符 
 int c = nextNonWhitespace(true);
    switch (c) {
    case ']':
      if (peekStack == JsonScope.EMPTY_ARRAY) {
        return peeked = PEEKED_END_ARRAY;
      }
      // fall-through to handle ",]"
    case ';':
    case ',':
      // In lenient mode, a 0-length literal in an array means 'null'.
      if (peekStack == JsonScope.EMPTY_ARRAY || peekStack == JsonScope.NONEMPTY_ARRAY) {
        checkLenient();
        pos--;
        return peeked = PEEKED_NULL;
      } else {
        throw syntaxError("Unexpected value");
      }
    case '\'':
      checkLenient();
      return peeked = PEEKED_SINGLE_QUOTED;
    case '"':
      return peeked = PEEKED_DOUBLE_QUOTED;
    case '[':
      return peeked = PEEKED_BEGIN_ARRAY;
    case '{':
      return peeked = PEEKED_BEGIN_OBJECT;
    default:
      pos--; // Don't consume the first character in a literal value.
    }
//若以上未消费,
int result = peekKeyword();//主要是处理true,false,null
    if (result != PEEKED_NONE) {
      return result;
    }

    result = peekNumber();//主要是处理int,short,byte,long,flat,double类型的
    if (result != PEEKED_NONE) {
      return result;
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值