问题描述
我需要以最少的礼节获得一个简单的JSON序列化解决方案.因此,我很高兴找到即将推出的Play 2.2库.这与普通情况下的类完美配合,例如
I need to get a simple JSON serialization solution with minimum ceremony. So I was quite happy finding this forthcoming Play 2.2 library. This works perfectly with plain case classes, e.g.
import play.api.libs.json._
sealed trait Foo
case class Bar(i: Int) extends Foo
case class Baz(f: Float) extends Foo
implicit val barFmt = Json.format[Bar]
implicit val bazFmt = Json.format[Baz]
但是以下操作失败:
implicit val fooFmt = Json.format[Foo] // "No unapply function found"
我将如何为Foo
设置所谓的丢失提取器?
How would I set up the alleged missing extractor for Foo
?
还是您会推荐任何其他或多或少地完全自动处理我的案件的独立库?我不在乎是在编译时使用宏还是在运行时使用反射,只要它开箱即用即可.
Or would you recommend any other standalone library that handles my case more or less fully automatically? I don't care whether that is with macros at compile time or reflection at runtime, as long as it works out of the box.
推荐答案
以下是Foo
随播对象的手动实现:
Here is a manual implementation of the Foo
companion object:
implicit val barFmt = Json.format[Bar]
implicit val bazFmt = Json.format[Baz]
object Foo {
def unapply(foo: Foo): Option[(String, JsValue)] = {
val (prod: Product, sub) = foo match {
case b: Bar => (b, Json.toJson(b)(barFmt))
case b: Baz => (b, Json.toJson(b)(bazFmt))
}
Some(prod.productPrefix -> sub)
}
def apply(`class`: String, data: JsValue): Foo = {
(`class` match {
case "Bar" => Json.fromJson[Bar](data)(barFmt)
case "Baz" => Json.fromJson[Baz](data)(bazFmt)
}).get
}
}
sealed trait Foo
case class Bar(i: Int ) extends Foo
case class Baz(f: Float) extends Foo
implicit val fooFmt = Json.format[Foo] // ça marche!
验证:
val in: Foo = Bar(33)
val js = Json.toJson(in)
println(Json.prettyPrint(js))
val out = Json.fromJson[Foo](js).getOrElse(sys.error("Oh no!"))
assert(in == out)
或者直接格式定义:
Alternatively the direct format definition:
implicit val fooFmt: Format[Foo] = new Format[Foo] {
def reads(json: JsValue): JsResult[Foo] = json match {
case JsObject(Seq(("class", JsString(name)), ("data", data))) =>
name match {
case "Bar" => Json.fromJson[Bar](data)(barFmt)
case "Baz" => Json.fromJson[Baz](data)(bazFmt)
case _ => JsError(s"Unknown class '$name'")
}
case _ => JsError(s"Unexpected JSON value $json")
}
def writes(foo: Foo): JsValue = {
val (prod: Product, sub) = foo match {
case b: Bar => (b, Json.toJson(b)(barFmt))
case b: Baz => (b, Json.toJson(b)(bazFmt))
}
JsObject(Seq("class" -> JsString(prod.productPrefix), "data" -> sub))
}
}
现在理想情况下,我想自动生成apply
和unapply
方法.看来我将需要使用反射或深入研究宏.
Now ideally I would like to automatically generate the apply
and unapply
methods. It seems I will need to use either reflection or dive into macros.
这篇关于带有Play 2.2库的密封特性的无噪声JSON格式的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!