反序列化
Gson所做的反序列化工作大致如下:
json本质上讲是一个结构型的文本。而Gson的核心功能之一,也是词法分析。以下是json文法。
object = {} | { members }
members = pair | pair , members
pair = string : value
array = [] | [ elements ]
elements = value | value , elements
value = string | number | object | array | true | false | null
string = "" | " chars "
chars = char | char chars
char = any-Unicode-character-except-"-or-\-or- control-character | \" | \\ | \/ | \b | \f | \n | \r | \t | \u four-hex-digits
number = int | int frac | int exp | int frac exp
int = digit | digit1-9 digits | - digit | - digit1-9 digits
frac = . digits
exp = e digits
digits = digit | digit digits
e = e | e+ | e- | E | E+ | E-
词法分析的任务是要解析出Token流,Token是一个二元组,由符号和种别码构成。
public enum JsonToken {
BEGIN_ARRAY, //数组开始
END_ARRAY,//数组结束
BEGIN_OBJECT,//对象开始
END_OBJECT,//对象结束
NAME,//键和值
STRING,//字符串
NUMBER,//数字
BOOLEAN,//布尔型
NULL,//空
END_DOCUMENT//文本结束
}
JsonToken中包含json字符串中的所有情况。JsonScope定义了token的种别码。
final class JsonScope {
static final int EMPTY_ARRAY = 1;
static final int NONEMPTY_ARRAY = 2;
static final int EMPTY_OBJECT = 3;
static final int DANGLING_NAME = 4;
static final int NONEMPTY_OBJECT = 5;
static final int EMPTY_DOCUMENT = 6;
static final int NONEMPTY_DOCUMENT = 7;
static final int CLOSED = 8;
}
其中DANGLING_NAME通俗点讲就是key,当出现这种类型的字串,接下来解析出来的便是value。
解析的核心部分放在JsonReader中:
public JsonToken peek() throws IOException {
int p = peeked;
if (p == PEEKED_NONE) {
p = doPeek();
}
switch (p) {
case PEEKED_BEGIN_OBJECT:
return JsonToken.BEGIN_OBJECT;
case PEEKED_END_OBJECT:
return JsonToken.END_OBJECT;
case PEEKED_BEGIN_ARRAY:
return JsonToken.BEGIN_ARRAY;
case PEEKED_END_ARRAY:
return JsonToken.END_ARRAY;
case PEEKED_SINGLE_QUOTED_NAME:
case PEEKED_DOUBLE_QUOTED_NAME:
case PEEKED_UNQUOTED_NAME:
return JsonToken.NAME;
case PEEKED_TRUE:
case PEEKED_FALSE:
return JsonToken.BOOLEAN;
case PEEKED_NULL:
return JsonToken.NULL;
case PEEKED_SINGLE_QUOTED:
case PEEKED_DOUBLE_QUOTED:
case PEEKED_UNQUOTED:
case PEEKED_BUFFERED:
return JsonToken.STRING;
case PEEKED_LONG:
case PEEKED_NUMBER:
return JsonToken.NUMBER;
case PEEKED_EOF:
return JsonToken.END_DOCUMENT;
default:
throw new AssertionError();
}
}
变量p便是token的种别码。peek函数返回的是一个JsonToken,调用一次,返回一个,并非一次性全部解析完。PEEKED_NONE表示一次读取完毕,每次调用完,p都会被赋值为PEEKED_NONE,所以会调用doPeek():
int doPeek() throws IOException {
int peekStack = stack[stackSize - 1];
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();
if (result != PEEKED_NONE) {
return result;
}
result = peekNumber();
if (result != PEEKED_NONE) {
return result;
}
if (!isLiteral(buffer[pos])) {
throw syntaxError("Expected value");
}
checkLenient();
return peeked = PEEKED_UNQUOTED;
}
调用nextNonWhitespace返回一个字符,然后根据这个字符,返回不同的类型。JsonReader中定义如下:
private static final int PEEKED_NONE = 0;
private static final int PEEKED_BEGIN_OBJECT = 1;
private static final int PEEKED_END_OBJECT = 2;
private static final int PEEKED_BEGIN_ARRAY = 3;
private static final int PEEKED_END_ARRAY = 4;
private static final int PEEKED_TRUE = 5;
private static final int PEEKED_FALSE = 6;
private static final int PEEKED_NULL = 7;
private static final int PEEKED_SINGLE_QUOTED = 8;
private static final int PEEKED_DOUBLE_QUOTED = 9;
private static final int PEEKED_UNQUOTED = 10;
/** When this is returned, the string value is stored in peekedString. */
private static final int PEEKED_BUFFERED = 11;
private static final int PEEKED_SINGLE_QUOTED_NAME = 12;
private static final int PEEKED_DOUBLE_QUOTED_NAME = 13;
private static final int PEEKED_UNQUOTED_NAME = 14;
/** When this is returned, the integer value is stored in peekedLong. */
private static final int PEEKED_LONG = 15;
private static final int PEEKED_NUMBER = 16;
private static final int PEEKED_EOF = 17;
JsonReader中,读取字符流,然后根据json方法,生成Token。