/ / Spray-json десериализиращ вложен обект - json, scala, spray-json

Spray-json десериализиращ вложен обект - json, scala, spray-json

Как да десериализираме вградените обекти правилно в spray-json?

    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

На странична бележка как да се спре да сериализира картата с полета (с вложена карта за вложени обекти)?

Отговори:

16 за отговор № 1

Примерът по-долу показва JSON -> РезюмеСинтаксис Tree -> Scala Case Classes и обратно с имена на потребителски полета и поддръжка за незадължителни членове на класовете случаи. Примерът е получен от документацията на spray-json на https://github.com/spray/spray-json за версия 1.2.5.

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])
}

Примерът извежда следното при изпълнение:

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)

1 за отговор № 2

Към оставащия си въпрос - как да използвате повторно JSON реализациите в рамките на тип опаковане:

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

Бих променил това, за да:

"person-field" -> p.toJson

По този начин вие давате възможност Person клас клас JSONify, вместо да въвежда друг начин в обвиващия обект. DRY и по-прости.

И:

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

Използвай .convertTo[Person] тук:

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

Ако има проблеми, моля попитайте за допълнителна помощ. Имам подобна структура в собствения си проект, но не се опитах да ги изпълня в този контекст.