2013-02-05 33 views
1

當我的應用程序在語法上不正確JSON時,我希望能夠向用戶報告錯誤,並提供一些有用的詳細信息,以允許找到問題區域。如何在使用JSON.parseFull和Scala時報告解析錯誤

所以在這個例子中,由於「File1」後面的尾隨逗號,j將爲None。有沒有辦法獲得最後解析錯誤的細節?

val badSyntax = """ 
{ 
    "menu1": { 
    "id": "file1", 
    "value": "File1", 
    }, 
    "menu2": { 
    "id": "file2", 
    "value": "File2", 
    } 
}""" 

    val j = JSON.parseFull(badSyntax) 

回答

2

當您收到解析錯誤時,請使用JSON.lastNoSuccess獲取最後一個錯誤。它的類型爲JSON.NoSuccess,其中有兩個子類,JSON.ErrorJSON.Failure,都包含msg: String成員詳述錯誤。 注意JSON.lastNoSuccess不是線程安全的(這僅僅是一種全局變量)和現在已經過時(綁定在斯卡拉2.11消失)

UPDATE:很顯然,我誤以爲這不是線程安全的:它在scala 2.10之前確實不是線程安全的,但現在lastNoSuccess由線程局部變量支持(因此在多線程上下文中安全使用)。 這樣做後,你會被原諒,認爲只要你在解析失敗在與解析(你調用parseFull的線程)所在的線程相同的線程中讀取,那麼所有東西將按預期工作。不幸的是,這個重構過程中,他們也改變了他們如何使用lastNoSuccess內部內Parsers.phrase(由JSON.parseFull調用。 見https://github.com/scala/scala/commit/1a4faa92faaf495f75a6dd2c58376f6bb3fbf44c 因爲這個重構,lastNoSuccess重置爲NoneParsers.phrase末,這是沒有問題的解析器在一般情況下,爲lastNoSuccess被用作返回作爲Parsers.phrase反正結果的臨時值。 這裏的問題是,我們不叫Parsers.phrase,但JSON.parseFull,其下降的任何錯誤信息(見case None => None裏面方法JSON.parseRawhttps://github.com/scala/scala/blob/v2.10.0/src/library/scala/util/parsing/json/JSON.scala) 。 JSON.parseFull錯誤的事實在scala 2.10之前,通過直接讀取JSON.lastNoSuccess就可以很容易地避開fo,但現在該值在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 
    } 
} 

我只是改變OptionEither的結果類型,這樣我就可以返回解析錯誤作爲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 
     ^) 
+0

感謝您的答案,但它不適用於我的2.10.0。解析不良數據後,'JSON.lastNoSuccess'爲'null'。 –

+0

確實,我現在可以證實這一點。我做了一個(冗長的)更新,請看看。 –

+0

這是爲我工作。 –