使用Play的2.2版Scala JSON组合器写出案例类中找不到的任意值

时间:2014-04-11 17:57:33

标签: json scala playframework functional-programming combinators

我想实现一个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调用产生CanBuild3Foo的{​​{1}}会产生unapply。我考虑在结果中附加一个值,生成Tuple2,但我发现looks pretty badlanguage maintainers will not implement it

有很多方法可以解决这个问题,但是我不想用我想添加到生成的JSON中的这些装饰器值来污染我的模型类。

有什么建议吗?

值得注意的是可以朝另一个方向发展,为{J}中不存在但由结果对象指定值的情况提供值Tuple3

2 个答案:

答案 0 :(得分: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)只是将函数从Foo转换为前面的applicative builder表达式所需类型的元组的一种奇特方式,你可以将它替换为你自己的函数添加你想要的任何东西。

如果确实想要更清晰的语法,您可以使用Shapeless

import shapeless.syntax.std.tuple._

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

它很美,但可能有点过分。

答案 1 :(得分: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))