2025年Gson中JsonReader的源码解析

Gson中JsonReader的源码解析JsonReader 的源码解析 JsonReader 是用来反序列化 Json 字符串的主要类 重点属性 stack 一个 int 数组 默认 32 位 stackSize 栈的长度 Peeked 当前字符的状态 一共有 17 种状态 状态 值 作用 PEEKED NONE 0

大家好,我是讯享网,很高兴认识大家。

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; } 
小讯
上一篇 2025-03-28 09:42
下一篇 2025-04-10 21:43

相关推荐

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