2014-02-11 1 views
9

Wie entesterte Objekte in Spray-Json korrekt deserialisieren?Spray-Json Deserialisierung verschachteltes Objekt

import spray.json._ 

    case class Person(name: String) 

    case class Color(n: String, r: Int, g: Int, b: Int, p: Person) 

    object MyJsonProtocol extends DefaultJsonProtocol { 

     implicit object ColorJsonFormat extends RootJsonFormat[Color] { 
     def write(c: Color) = JsObject(
      "color-name" -> JsString(c.n), 
      "Green" -> JsNumber(c.g), 
      "Red" -> JsNumber(c.r), 
      "Blue" -> JsNumber(c.b), 
      "person-field" -> JsObject("p-name" -> JsString(c.p.name)) 
     ) 

     def read(value: JsValue) = { 
      value.asJsObject.getFields("color-name", "Red", "Green", "Blue", "person-field") match { 
      case Seq(JsString(name), JsNumber(red), JsNumber(green), JsNumber(blue), JsObject(person)) => 
       Color(name, red.toInt, green.toInt, blue.toInt, null) //gotta replace null with correct deserializer 
      case _ => throw new DeserializationException("Color expected") 
      } 
     } 
     } 

    } 

    import MyJsonProtocol._ 

    val jsValue = Color("CadetBlue", 95, 158, 160, Person("guest")).toJson 

    jsValue.prettyPrint 

    val color = jsValue.convertTo[Color] //person is missing of course 

An einer Nebennote, wie Sprühen json Hilfe (mit verschachtelter Karte für verschachtelte Objekte) auf eine Karte von Feldern Serialisierung?

Antwort

15

Das folgende Beispiel zeigt JSON -> Abstract Syntax Tree -> Scala-Fallklassen und zurück mit benutzerdefinierten Feldnamen und Unterstützung für optionale Fallklassenmitglieder. Das Beispiel ist aus der spray-json Dokumentation unter https://github.com/spray/spray-json für Version 1.2.5 abgeleitet.

package rando 

import spray.json._ 

case class Color(name: String, red: Int, green: Int, blue: Int) 

case class Team(name: String, color: Option[Color]) 

object MyJsonProtocol extends DefaultJsonProtocol { 
    implicit val colorFormat = jsonFormat(Color, "name", "r", "g", "b") 
    implicit val teamFormat = jsonFormat(Team, "name", "jersey") 
} 
import MyJsonProtocol._ 

object GoSox extends App { 
    val obj = Team("Red Sox", Some(Color("Red", 255, 0, 0))) 
    val ast = obj.toJson 
    println(obj) 
    println(ast.prettyPrint) 
    println(ast.convertTo[Team]) 
    println("""{ "name": "Red Sox", "jersey": null }""".asJson.convertTo[Team]) 
    println("""{ "name": "Red Sox" }""".asJson.convertTo[Team]) 
} 

Das Beispiel gibt die folgende wenn sie ausgeführt werden:

Team(Red Sox,Some(Color(Red,255,0,0))) 
{ 
    "name": "Red Sox", 
    "jersey": { 
    "name": "Red", 
    "r": 255, 
    "g": 0, 
    "b": 0 
    } 
} 
Team(Red Sox,Some(Color(Red,255,0,0))) 
Team(Red Sox,None) 
Team(Red Sox,None) 
+0

Wie wäre es mit Option [Farbe]? So Team-Klasse wird Fall Klasse Team (Name: String, Farbe: Option [Color]) – user3103600

+0

Können Sie mir sagen, was Sie bereits ausprobiert haben? War die Dokumentation von spray-json hilfreich? –

+0

Ich möchte Feldnamen während der Serialisierung anpassen. – user3103600

1

Um weitere Frage - wie innerhalb eines Umschlingungstyp JSON Konvertierungen wiederzuverwenden:

"person-field" -> JsObject("p-name" -> JsString(c.p.name)) 

Ich würde dies ändern:

"person-field" -> p.toJson 

Auf diese Weise lassen Sie die Person Fallklasse JSonify sich selbst, anstatt einen anderen Weg in das Wrapping-Objekt einzuführen. DRY und einfacher.

Und:

case Seq(JsString(name), JsNumber(red), JsNumber(green), JsNumber(blue), JsObject(person)) => 
    Color(name, red.toInt, green.toInt, blue.toInt, null) 

Verwenden Sie die .convertTo[Person] hier:

case Seq(JsString(name), JsNumber(red), JsNumber(green), JsNumber(blue), jsv) => 
    Color(name, red.toInt, green.toInt, blue.toInt, jsv.convertTo[Person]) 

Wenn es Probleme gibt, bitte für weitere Hilfe bitten. Ich habe eine ähnliche Struktur in meinem eigenen Projekt, aber ich habe nicht versucht, sie in diesem Kontext auszuführen.

Verwandte Themen