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;
}