2

ich implicit val reads bin mit abzubilden Json wie:scala Spiel verschachtelte json liest analysieren

{ 
    "id": 1 
    "friends": [ 
    { 
     "id": 1, 
     "since": ... 
    }, 
    { 
     "id": 2, 
     "since": ... 
    }, 
    { 
     "id": 3, 
     "since": ... 
    } 
    ] 
} 

auf einen Fall Klasse

case class Response(id: Long, friend_ids: Seq[Long]) 

Ich kann es nur mit einem Zwischenklasse machen arbeiten, die das widerspiegelt JSON friends Struktur. Aber ich benutze es nie in meiner App. Gibt es eine Möglichkeit, ein Reads[Response]-Objekt zu schreiben, so dass meine Antwortklasse direkt dem angegebenen JSON zugeordnet würde?

+0

so etwas wie 'case class Response (id: Long, Freunde: Seq [Friend])'? – mfirry

+0

das funktioniert, aber ich habe nicht und möchte nicht erstellen "Friend" -Klasse. Ich brauche nur ihre IDs –

Antwort

3

Sie brauchen nur einfache [Antwort] Lesen mit expliziten Reads.seq() für friend_ids wie

val r: Reads[Response] = (
    (__ \ "id").read[Long] and 
    (__ \ "friends").read[Seq[Long]](Reads.seq((__ \ "id").read[Long])) 
)(Response.apply _) 

und Ergebnis wird sein:

r.reads(json) 

scala> res2: play.api.libs.json.JsResult[Response] = JsSuccess(Response(1,List(1, 2, 3)),) 
1

können Sie versuchen, den folgenden

@annotation.tailrec 
def go(json: Seq[JsValue], parsed: Seq[Long]): JsResult[Seq[Long]] = 
    json.headOption match { 
    case Some(o @ JsObject(_)) => (o \ "id").validate[Long] match { 
     case JsError(cause) => JsError(cause) 
     case JsSuccess(id) => go(json.tail, parsed :+ id) 
    } 
    case Some(js) => JsError(s"invalid friend JSON (expected JsObject): $js") 
    case _ => JsSuccess(parsed) // nothing more to read (success) 
    } 

implicit val friendIdReader = Reads[Seq[Long]] { 
    case JsArray(values) => go(values, Nil) 
    case json => JsError(s"unexpected JSON: $json") 
} 

implicit val responseReader = Json.reads[Response] 
// responseReader will use friendIdReader as Reads[Seq[Long]], 
// for the property friend_ids 
+0

Danke für Ihren Vorschlag! Das wird wahrscheinlich funktionieren, aber ich würde lieber mit einer Utility-Klasse (z. B. "Friend") gehen, wenn es keinen einfacheren Weg dafür gibt. Und ich nehme an, da ist keiner. –

1

Den einfachen Weg sein könnte:

import play.api.libs.functional.syntax._ 
import play.api.libs.json.{JsValue, Json, _} 


case class Response(id: Long, friend_ids: Seq[Friends]) 

object Response { 

    implicit val userReads: Reads[Response] = (
    (JsPath \ "id").read[Long] and 
     (JsPath \ "friends").read[Seq[Friends]] 
    ) (Response.apply _) 
} 

case class Friends(id: Long, since: String) 
object Friends { 
    implicit val fmt = Json.format[Friends] 
} 

ohne case class Friends Ich finde es schwieriger, eine Lösung zu finden, aber wenn ich einen Post finden

Edit: Hinzugefügt Link für Antwort auf Scala neu bearbeiten

Also, ich wollte ein bisschen mehr darüber verstehen, wie JSON zu Modellen zu parsen, und beschlossen, auf Reedit zu fragen. Erhielt ein paar ziemlich coole Links, einen Blick:

https://www.reddit.com/r/scala/comments/4bz89a/how_to_correctly_parse_json_to_scala_case_class/