我们是用Play的JSON序列化来序列化一个模型。
case class Foo(
var id: Long,
var birthday: Date,
[...]
)
object Foo {
implicit val fooFormat: OFormat[Foo] = Json.format[Foo]
}
然而我们想添加一些计算值,例如。
case class Foo(
...
) {
def age: Int = 32
}
为了在序列化中包含年龄,似乎我们必须通过写出一个完整的Writesunapply方法来重复所有的字段名。
implicit val fooWrites: Writes[Foo] = (
(JsPath \ "id").write[Long] and
(JsPath \ "birthday").write[Date] and
[...]
(JsPath \ "age").write[Int]
)(unlift(Foo.unapply_extended))
def unapply_extended(a: Foo): Option[(Long,Date,[...],Int)] = Some(( a.id, a.birthday, [...], a.age))
implicit val fooReads = Json.reads[Foo]
有没有一种方法可以在JSON序列化中包含计算出的年龄值,而不需要多次重新列举相同的case类fieldstypes? 当有很多字段时,很快就会变得无法管理,所有的信息都是多余的。
我不认为这是不可能的,因为生成的编解码器是针对普通用例(case类及其字段)进行优化的。但你可以推导出编解码器,并在事后通过使用 变压器.
case class Foo(
...
) {
def age: Int = 32
}
object Foo {
implicit val fooFormat: OFormat[Foo] = {
val derived = Json.format[Foo] // majority of work done here
// here we just modify output of writer to add that one field
OFormat(
r = derived,
w = foo => Json.writes[Foo].transform { json: JsObject =>
json.transform((__ \ 'age).json.put(JsNumber(foo.age))).getOrElse(json)
}.writes(foo)
)
}
}
如果你分别推导出Reads和Writes,你可以节省一两行。
object Foo {
implicit val fooFormat: OFormat[Foo] = OFormat(
r = Json.reads[Foo],
w = foo => Json.writes[Foo].transform { json: JsObject =>
json.transform((__ \ 'age).json.put(JsNumber(foo.age))).getOrElse(json)
}.writes(foo)
)
}