当您收到解析错误时,使用JSON.lastNoSuccess获取最后一个错误。它的类型JSON.NoSuccess是两个子类,JSON.Error并且JSON.Failure都包含一个msg: String详细说明错误的成员。请注意,JSON.lastNoSuccess它不是线程安全的(它只是一个全局变量)并且现在已被弃用(在 scala 2.11 中必然会消失)
更新:显然,我错认为它不是线程安全的:在 scala 2.10 之前它确实不是线程安全的,但现在lastNoSuccess由线程局部变量支持(因此在多线程上下文中使用是安全的) . 看到这个之后,您会认为只要您在与用于进行解析的线程(您调用的线程)相同的线程中parseFull解析失败后立即阅读,那么一切都会按预期工作.
不幸的是,在此重构期间,他们还更改了内部使用的方式lastNoSuccess(Parsers.phrase由JSON.parseFull.lastNoSuccessNoneParsers.phrase. 这在解析器中一般来说没有问题,因为lastNoSuccess它被用作作为结果返回的临时值Parsers.phrase。
这里的问题是我们不调用Parsers.phrase, but JSON.parseFull,这会丢弃任何错误信息(参见https://github.com/scala/scala/blob/v2.10.0/src/library/scala/util/parsing的case None => None内部方法/json/JSON.scala)。在 scala 2.10 之前,可以按照我之前的建议通过直接读取来轻松规避删除任何错误信息的事实,但是现在这个值在.JSON.parseRawJSON.parseFullJSON.lastNoSuccessParsers.phraseJSON
有什么解决办法吗?是的。您可以做的是创建您自己的版本JSON,不会丢弃错误信息:
import util.parsing.json._
object MyJSON extends Parser {
def parseRaw(input : String) : Either[NoSuccess, JSONType] = {
phrase(root)(new lexical.Scanner(input)) match {
case Success(result, _) => Right(result)
case ns: NoSuccess => Left(ns)
}
}
def parseFull(input: String): Either[NoSuccess, Any] = {
parseRaw(input).right.map(resolveType)
}
def resolveType(input: Any): Any = input match {
case JSONObject(data) => data.transform {
case (k,v) => resolveType(v)
}
case JSONArray(data) => data.map(resolveType)
case x => x
}
}
我只是更改Option为Either作为结果类型,这样我就可以将解析错误作为Left. REPL 中的一些测试:
scala> MyJSON.parseFull("[1,2,3]")
res11: Either[MyJSON.NoSuccess,Any] = Right(List(1.0, 2.0, 3.0))
scala> MyJSON.parseFull("[1,2,3")
res12: Either[MyJSON.NoSuccess,Any] =
Left([1.7] failure: end of input
[1,2,3
^)