解析エラーが発生した場合はJSON.lastNoSuccess
、最後のエラーを取得するために使用します。JSON.NoSuccess
これは、 2 つのサブクラスおよびのタイプでJSON.Error
ありJSON.Failure
、両方ともmsg: String
エラーの詳細を示すメンバーを含んでいます。これJSON.lastNoSuccess
はスレッドセーフではなく (単なるグローバル変数です)、現在は推奨されていません (scala 2.11 では消える予定です)。
UPDATE :どうやら、スレッドセーフではないという点で間違っていたようです。実際、scala 2.10 より前はスレッドセーフではありませんでしたが、現在lastNoSuccess
はスレッドローカル変数によってサポートされています (したがって、マルチスレッドコンテキストで安全に使用できます)。 . これを見た後、解析に使用されたスレッド ( を呼び出したスレッド)と同じスレッドで解析が失敗した直後に読む限りparseFull
、すべてが期待どおりに機能すると考えることができます。 .
残念ながら、このリファクタリングlastNoSuccess
中に、内部での使用方法も変更されParsers.phrase
ました (これは によって呼び出されますJSON.parseFull
。lastNoSuccess
None
Parsers.phrase
. lastNoSuccess
とにかくの結果として返される一時的な値として使用されるため、これは一般的なパーサーでは問題ありませParsers.phrase
ん。
ここでの問題は、 を呼び出さずに を呼び出しParsers.phrase
、JSON.parseFull
エラー情報をドロップすることです( https://github.com/scala/scala/blob/v2.10.0/src/library/scala/util/parsingcase None => None
の内部メソッドJSON.parseRaw
を参照してください)。 /json/JSON.scala )。scala 2.10 より前のバージョンでは、エラー情報をドロップするという事実は、以前にアドバイスしたように、JSON.parseFull
直接読み取ることで簡単に回避できましJSON.lastNoSuccess
たが、この値は の最後でリセットされるParsers.phrase
ため、 からエラー情報を取得するためにできることはあまりありませんJSON
。
解決策はありますか?はい。できることは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
^)