2014-09-01 53 views
3

歡迎,與Scala玩2.3,把JSON數組轉換成序列

我真的很想避免這個,但是我現在放棄了。我試圖遍歷json數組並提取一些元素並將它們按順序排列。我嘗試了很多選擇,嘗試了所有從遊戲文檔,許多嘗試,但仍然有同樣的錯誤:當我的方法試圖提取元素時出現空指針異常。所以我的JSON的例子是:

[ 
    { 
    "var1": "xx", 
    "var2": "xxx", 
    "var3": 111 
    }, 
    { 
    "var1": "yy", 
    "var2": "yyy", 
    "var3": 222 
    }, 
    { 
    "var1": "zz", 
    "var2": "zzz", 
    "var3": 333  
    } 
] 

我定義讀取的許多配置,最後一個是這樣的,但不想要,甚至編譯/

case class Vars1(vars: Seq[String]) 
val var1Reads: Reads[String] = (__ \ "var1").read[String] 
implicit val vars1Reads: Reads[Vars1] = ((__).read[Seq[String]])(Vars1.apply _) 

我想創建序列或名單,這不重要的是,從這個數組的每個元素只有var1。它可以是純序列,或序列或其他的案例類。只是如何遍歷json數組?我嘗試了很多配置,閱讀var1是沒有問題的,但是當我想從數組的每個元素讀取所有變量1時,我有空指針異常。請任何人都可以指出我的方向,給我一個暗示我做錯了什麼?請不要怪我在編程方面是新手,我開始學習Scala和玩框架。

謝謝你的幫助。

更新:

我已經試過這一個了:

implicit val vars1Reads = (__).read(Reads.list((__).read[String])).map(var => Vars(var)) 

但我仍然有同樣的錯誤:

[NoSuchElementException: JsError.get] 
+0

聲明你的讀取是懶惰的,例如'隱式lazy val vars1Reads'。這是一個惱人的,完全混淆NPE的來源。 – Ryan 2014-09-01 20:40:30

回答

3

解析這個的最簡單的方法是讓遊戲解析數組體爲Seq[_],即一系列對象。

我建議您的數組中的每個項目都應該由案例類別來表示,例如,

case class Var1(var1: String) 

這提供了一種有用的類型,可以在其上添加來自JSON的輸入數據的驗證。

您可以在適當的位置添加隱式Reads,例如,

object Var1 { 
    implicit val var1Reads: Reads[Var1] = { 
    ((__ \ "var1").read[String]).map(Var1.apply _) 
    } 
} 

注意,讀/寫宏有一個限制,他們不在的情況下類有單場記錄的工作方式 - 看http://grokbase.com/t/gg/play-framework/131bx7pcyd/play2-1-scala-json-writing-a-reads-writes-for-a-single-field-case-class - 這就是爲什麼加入map電話。當有兩個或更多字段時,宏應該按照記錄工作。

然後,您可以使用它創建一個Seq [Var1],例如

def test = Action(BodyParsers.parse.json) { request => 
    val result = request.body.validate[Seq[Var1]] 
    ... 
} 

而結果(這裏我只是打印出結果的值。的toString)是:

$ curl --include --request POST --header "Content-type: application/json" --data '[{"var1": "3", "var2": "4"}, {"var1": "7"}]' http://localhost:9000/test 
HTTP/1.1 200 OK 
Content-Type: text/plain; charset=utf-8 
Content-Length: 34 

JsSuccess(List(Var1(3), Var1(7)),) 

更新

如在下面的評論中提到,你可以使用這樣的宏簡化Reads[Var1]實現:

implicit val var1Reads = Json.reads[Var1] 

這隻會做你想要,如果該字段被稱爲var1,即

case class Var1(var1: String) 
+0

根據[文檔](https://www.playframework.com/documentation/2.3.x/ScalaJsonInception),2.1-RC2版本修復了單字段大小寫類的限制。 – 2014-09-01 13:34:05

+0

它的確如此。但是,'((__ \「var1」).read [String])(Var1.apply _)'導致編譯錯誤'重載的方法值[read]不能應用於(String => controllers.Var1)',而適用於多個領域的相同模式確實有效(Play 2.3.4)。我目前的假設是,並非所有的情況都是固定的,但需要更多的調查。 – 2014-09-01 13:54:29

+0

啊,我認爲那個固定的東西是宏觀世代,例如'隱式val var1Reads = Json.reads [Var1]'。我可以證實它的工作原理。我發現宏代的可靠性足夠我不需要編寫自己的代碼。 – 2014-09-01 14:07:55