带有 Play 2.2 库的密封特征的无噪声 JSON 格式 [英] Noise free JSON format for sealed traits with Play 2.2 library

查看:13
本文介绍了带有 Play 2.2 库的密封特征的无噪声 JSON 格式的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我需要以最少的仪式获得一个简单的 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))
  }
}

<小时>

现在理想情况下,我想自动生成 applyunapply 方法.看来我需要使用反射或深入研究宏.


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 格式的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆