Jackson 的 JSON (2.5.0) 验证未按预期工作
Jackson's JSON (2.5.0) validation not working as expected
简单测试用例:
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
public static void main(String[] args) throws Exception {
String json = "1,2";
ObjectMapper parser = new ObjectMapper();
JsonNode rootNode = parser.readTree(json);
}
抛出异常:
Exception in thread "main" com.fasterxml.jackson.core.JsonParseException:
Unexpected character (',' (code 44)): Expected space separating root-level values
at [Source: 1,2; line: 1, column: 3]
一切都很好,但如果我将 String json
更改为以下任何一项:
String json = "null,false";
String json = "[1,2,3,null,\"hello\"],false";
String json = "true,3";
String json = "true,{\"test\":3}";
没有抛出异常。
为什么会出现差异?
Jackson默认使用ReaderBasedJsonParser
,其中,当reading/initing JSON被解析时,有显式检查
switch (i) {
case '"':
_tokenIncomplete = true;
t = JsonToken.VALUE_STRING;
break;
case '[':
if (!inObject) {
_parsingContext = _parsingContext.createChildArrayContext(_tokenInputRow, _tokenInputCol);
}
t = JsonToken.START_ARRAY;
break;
case '{':
if (!inObject) {
_parsingContext = _parsingContext.createChildObjectContext(_tokenInputRow, _tokenInputCol);
}
t = JsonToken.START_OBJECT;
break;
case ']':
case '}':
// Error: neither is valid at this point; valid closers have
// been handled earlier
_reportUnexpectedChar(i, "expected a value");
case 't':
_matchTrue();
t = JsonToken.VALUE_TRUE;
break;
case 'f':
_matchFalse();
t = JsonToken.VALUE_FALSE;
break;
case 'n':
_matchNull();
t = JsonToken.VALUE_NULL;
break;
case '-':
/* Should we have separate handling for plus? Although
* it is not allowed per se, it may be erroneously used,
* and could be indicate by a more specific error message.
*/
t = _parseNegNumber();
break;
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
t = _parsePosNumber(i);
break;
从上面的代码中您可以看到它会检查您提到的字符 - null、true、{、[、false 等。如果有任何匹配,它 returns 有效 json令牌。这就是为什么,如果你改变
String json = "true,3";
到
String json = "3,true";
它将再次抛出众所周知的异常。
请注意,还会检查以字母 "n" 开头的给定字符串,验证它是否与 null 匹配(对以 "t"、"f" 开头的字符串进行相同的检查).
然后有趣的是 _parsePosNumber(i)
方法,它基本上调用 _reportMissingRootWS
来检查根 - 但显然失败了。
所以基本上,如果 json 有效,它永远不会达到 "failer" 的情况,或者如果给定的字符串以 "true"、"false"、[=39 中的一个开头=], "[", "{", "]", "}" 它也会被认为是有效的 json。
我假设此功能在 Jackson non standard features 的列表中,因此上述格式被认为是有效的 JSON。
简单测试用例:
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
public static void main(String[] args) throws Exception {
String json = "1,2";
ObjectMapper parser = new ObjectMapper();
JsonNode rootNode = parser.readTree(json);
}
抛出异常:
Exception in thread "main" com.fasterxml.jackson.core.JsonParseException:
Unexpected character (',' (code 44)): Expected space separating root-level values
at [Source: 1,2; line: 1, column: 3]
一切都很好,但如果我将 String json
更改为以下任何一项:
String json = "null,false";
String json = "[1,2,3,null,\"hello\"],false";
String json = "true,3";
String json = "true,{\"test\":3}";
没有抛出异常。
为什么会出现差异?
Jackson默认使用ReaderBasedJsonParser
,其中,当reading/initing JSON被解析时,有显式检查
switch (i) {
case '"':
_tokenIncomplete = true;
t = JsonToken.VALUE_STRING;
break;
case '[':
if (!inObject) {
_parsingContext = _parsingContext.createChildArrayContext(_tokenInputRow, _tokenInputCol);
}
t = JsonToken.START_ARRAY;
break;
case '{':
if (!inObject) {
_parsingContext = _parsingContext.createChildObjectContext(_tokenInputRow, _tokenInputCol);
}
t = JsonToken.START_OBJECT;
break;
case ']':
case '}':
// Error: neither is valid at this point; valid closers have
// been handled earlier
_reportUnexpectedChar(i, "expected a value");
case 't':
_matchTrue();
t = JsonToken.VALUE_TRUE;
break;
case 'f':
_matchFalse();
t = JsonToken.VALUE_FALSE;
break;
case 'n':
_matchNull();
t = JsonToken.VALUE_NULL;
break;
case '-':
/* Should we have separate handling for plus? Although
* it is not allowed per se, it may be erroneously used,
* and could be indicate by a more specific error message.
*/
t = _parseNegNumber();
break;
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
t = _parsePosNumber(i);
break;
从上面的代码中您可以看到它会检查您提到的字符 - null、true、{、[、false 等。如果有任何匹配,它 returns 有效 json令牌。这就是为什么,如果你改变
String json = "true,3";
到
String json = "3,true";
它将再次抛出众所周知的异常。
请注意,还会检查以字母 "n" 开头的给定字符串,验证它是否与 null 匹配(对以 "t"、"f" 开头的字符串进行相同的检查).
然后有趣的是 _parsePosNumber(i)
方法,它基本上调用 _reportMissingRootWS
来检查根 - 但显然失败了。
所以基本上,如果 json 有效,它永远不会达到 "failer" 的情况,或者如果给定的字符串以 "true"、"false"、[=39 中的一个开头=], "[", "{", "]", "}" 它也会被认为是有效的 json。
我假设此功能在 Jackson non standard features 的列表中,因此上述格式被认为是有效的 JSON。