2

我想实现一个Writes发出一个在被序列化的类中找不到的 JSON 对象。

对于案例类:

case class Foo(i:Int, s:String)

我正在寻找生产:

{
  "i": <int>,
  "s": "<string>",
  "other": "Some value."
}

天真的第一次尝试是:

val writes: Writes[Foo] = ((
  (__ \ "i").write[Int] and
    (__ \ "s").write[String] and
    (__ \ "other").write("Some value.")
  )(unlift(Foo.unapply))

自然,这不会编译,因为后续and调用会产生 aCanBuild3并且Foo'unapply会产生 a Tuple2。我曾考虑在结果中附加一个值,生成一个Tuple3,但我发现看起来很糟糕语言维护者不会实现它

有一些方法可以解决这个问题,但我不想用我想添加到结果 JSON 中的这些装饰器值污染我的模型类。

有什么建议么?

值得注意的是,您可以转向另一个方向,为Reads.pureJSON 中不存在值但由结果对象指定的情况提供值。

4

2 回答 2

3

您可以通过脱糖来非常简单地做到这一点:

val writes: Writes[Foo] = (
  (__ \ "i").write[Int] and
  (__ \ "s").write[String] and
  (__ \ "other").write[String]
)(foo => (foo.i, foo.s, "Some value."))

unlift(Foo.unapply)只是将函数从 a 获取Foo到前面应用构建器表达式所需类型的元组的一种奇特方式,您可以将其替换为您自己的函数,该函数可以添加您想要的任何内容。

如果你真的想要更简洁的语法,你可以使用Shapeless

import shapeless.syntax.std.tuple._

val writes: Writes[Foo] = (
  (__ \ "i").write[Int] and
  (__ \ "s").write[String] and
  (__ \ "other").write[String]
)(_ :+ "Some value.")

它很漂亮,但可能有点矫枉过正。

于 2014-04-11T18:34:45.967 回答
1

另一种选择是使用实现unapply返回额外值的对象构建器。这使 Writes 更清晰,但添加了一个新对象。我发现这很有用,因为 apply 和 unapply 方法都可以用于将数据额外按摩到最终对象中(例如:https ://stackoverflow.com/a/22504468/1085606 )

例子:

case class Foo(i: Int, s: String)

object FooBuilder {
  def unapply(foo: Foo): Option[(Int, String, String)] = {
    Some((foo.i, foo.s, "Some extra value"))
  }
}

val writes: Writes[Foo] = ((
  (__ \ "i").write[Int] and
    (__ \ "s").write[String] and
    (__ \ "other").write[String]
  )(unlift(FooBuilder.unapply))
于 2014-09-26T05:22:54.117 回答