关于 fastjson 异常 autoType is not support 问题分析解决

原创 fastjson

数据仓库数据抽取服务在不久前增加了 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);
如果觉得这对你有用,请随意赞赏,给与作者支持
评论 0
最新评论