JsonReader 的源码解析
JsonReader是用来反序列化Json字符串的主要类。
重点属性
stack: 一个int数组,默认32位
stackSize: 栈的长度
Peeked: 当前字符的状态 一共有17种状态
| 状态 | 值 | 作用 |
|---|---|---|
| PEEKED_NONE | 0 | |
| PEEKED_BEGIN_OBJECT | 1 | |
| PEEKED_END_OBJECT | 2 | |
| PEEKED_BEGIN_ARRAY | 3 | |
| PEEKED_END_ARRAY | 4 | |
| PEEKED_TRUE | 5 | |
| PEEKED_FALSE | 6 | |
| PEEKED_NULL | 7 | |
| PEEKED_SINGLE_QUOTED | 8 | |
| PEEKED_DOUBLE_QUOTED | 9 | |
| PEEKED_UNQUOTED | 10 | |
| PEEKED_BUFFERED | 11 | |
| PEEKED_SINGLE_QUOTED_NAME | 12 | |
| PEEKED_DOUBLE_QUOTED_NAME | 13 | |
| PEEKED_UNQUOTED_NAME | 14 | |
| PEEKED_NUMBER | 15 | |
| PEEKED_EOF | 16 |
JsonScope:8种状态,当前层级的状态peekStack
| 状态 | 值 |
|---|---|
| EMPTY_ARRAY | 1 |
| NONEMPTY_ARRAY | 2 |
| EMPTY_OBJECT | 3 |
| DANGLING_NAME | 4 |
| NONEMPTY_OBJECT | 5 |
| EMPTY_DOCUMENT | 6 |
| NONEMPTY_DOCUMENT | 7 |
| CLOSED | 8 |
重点方法:
- 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; }

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容,请联系我们,一经查实,本站将立刻删除。
如需转载请保留出处:https://51itzy.com/kjqy/61284.html