使用 Play 的 (2.2) Scala JSON 组合器编写案例类中未找到的任意值
-
21-12-2019 - |
题
我想实施一个 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
调用产生一个 CanBuild3
和 Foo
的 unapply
产生一个 Tuple2
. 。我考虑向结果附加一个值,产生一个 Tuple3
, ,但我发现 看起来很糟糕 和 语言维护者不会实施它.
有多种方法可以解决这个问题,但我不想用我想要添加到生成的 JSON 中的这些装饰器值来污染我的模型类。
有什么建议么?
值得注意的是你 能 走另一个方向,提供价值 Reads.pure
适用于 JSON 中不存在值但由结果对象指定的情况。
解决方案
您可以通过稍微脱糖来非常简单地做到这一点:
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
到前面的应用构建器表达式所需的元组,您可以将其替换为您自己的函数,该函数可以添加您想要的任何内容。
如果你 真的 想要更清晰的语法,你可以使用 无形的:
import shapeless.syntax.std.tuple._
val writes: Writes[Foo] = (
(__ \ "i").write[Int] and
(__ \ "s").write[String] and
(__ \ "other").write[String]
)(_ :+ "Some value.")
它很漂亮,但可能有点过分了。
其他提示
另一种选择是使用对象生成器来实现 unapply
返回额外的值。这使得写入更干净,但添加了一个新对象。我发现这很有用,因为 apply 和 unapp 方法都可以用于将数据额外按摩到最终对象中(例如: 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))
不隶属于 StackOverflow