关于 fastjson 异常 autoType is not support 问题分析解决
数据仓库数据抽取服务在不久前增加了 OrientDB
的支持,当时使用了 Orient 官方提供的 JDBC 接口,后来发现 Orient JDBC 真是垃圾到无法言语了,不能满足我们自动化的 ETL 需求。
后来和 Neo4j 一样,改用 Http REST API 来请求数据,使用 Jsoup + FastJson 配合来操作数据。
当使用 http://192.190.10.170:2480/listDatabases
来获取数据库列表的时候,FastJson 直接报错了。
后来定位到代码,JSONObject.parseObject
方法在解析 JSON 字符串的时候抛出异常:
com.alibaba.fastjson.JSONException: autoType is not support. d
at com.alibaba.fastjson.parser.ParserConfig.checkAutoType(ParserConfig.java:889)
at com.alibaba.fastjson.parser.DefaultJSONParser.parseObject(DefaultJSONParser.java:325)
at com.alibaba.fastjson.parser.DefaultJSONParser.parse(DefaultJSONParser.java:1335)
at com.alibaba.fastjson.parser.DefaultJSONParser.parse(DefaultJSONParser.java:1301)
at com.alibaba.fastjson.JSON.parse(JSON.java:152)
at com.alibaba.fastjson.JSON.parse(JSON.java:143)
at com.alibaba.fastjson.JSON.parseObject(JSON.java:216)
at com.spinfosec.core.service.nosql.OrientInfoServiceImpl.schemas(OrientInfoServiceImpl.java:112)
at com.spinfosec.service.database.impl.DatabaseServiceImpl.schemas(DatabaseServiceImpl.java:594)
at com.spinfosec.service.database.thrift.DatabaseService$Processor$schemas.getResult(DatabaseService.java:877)
at com.spinfosec.service.database.thrift.DatabaseService$Processor$schemas.getResult(DatabaseService.java:862)
at org.apache.thrift.ProcessFunction.process(ProcessFunction.java:39)
at org.apache.thrift.TBaseProcessor.process(TBaseProcessor.java:39)
at org.apache.thrift.server.TThreadPoolServer$WorkerProcess.run(TThreadPoolServer.java:286)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at java.lang.Thread.run(Thread.java:745)
获取数据库列表的代码:
try
{
String url = this.driver.getUrl() + "/listDatabases";
Document document = Jsoup.connect(url)
.header("Authorization", this.driver.getAuthorization())
.header("Accept", "application/json; charset=UTF-8")
.ignoreContentType(true)
.get();
JSONObject response = JSONObject.parseObject(document.body().text());
JSONArray databases = response.getJSONArray("databases");
databases.toJavaList(String.class)
.stream()
.filter(Objects::nonNull)
.forEach(userDefList::add);
}
catch (Exception e)
{
logger.error("orient list databases error: ", e);
}
从异常日志可以看出,错误出在下面的代码处。
JSONObject response = JSONObject.parseObject(document.body().text());
断点查看 document.body().text()
返回的 JSON 字符串为:
{
"@type": "d",
"@version": 0,
"databases": [
"ank",
"demo",
"demo1",
"GratefulDeadConcerts",
"LIU"
]
}
“autoType is not support” 错误放生在 ParserConfig.checkAutoType
方法中。
根据错误堆栈回溯,核心错误发生在 DefaultJSONParser.java
323行,跟进源码:
在方法 DefaultJSONParser.parseObject
中,判断如果 json 的 key 的内容等于 @type
,并且并没有禁用 DisableSpecialKeyDetect
这个关键字检测,则会进行特殊类型反序列化处理,也就是 325 行,在这里 fastjson 自己定义了一个特殊的关键字 @type
用于保留反序列化时类型信息,而我们返回的 json 内容中恰好就含有这样的关键字,fastjson 当成了自己的预定义解析类型进行解析,故会报出刚才的错误。
根据以上代码的提示,可以在进行 JSON 解析的时候,将 Feature.DisableSpecialKeyDetect
传入解析器中,设置禁用关键字解析。
JSONObject response = JSONObject.parseObject(document.body().text(), Feature.DisableSpecialKeyDetect);