如何在使用组合器时写入JSON之前处理对象字段值

时间:2014-09-06 06:14:25

标签: scala playframework playframework-2.0 playframework-2.3

这是一个人为的例子来说明这一点。我知道我可以使用LocalDate和LocalTime来帮助代替DateTime,但是这将错过问题的重点,即在将它们写出来之前以某种方式处理字段值的方式。

case class Test(
    id: Long, dateOnly: DateTime, timeOnly: DateTime, comments: Option[String])

要将其写为JSON,我从这开始:

implicit val testWrites: Writes[Test] = (
    (__ \ "id"       ).write[Long]           and
    (__ \ "dateOnly" ).write[DateTime]       and
    (__ \ "timeOnly" ).write[DateTime]       and
    (__ \ "comments" ).write[Option[String]]
)(unlift(Test.unapply))

另外,假设一个没有注释的对象实例。

这将输出如下内容:

{"id": 123, 
 "dateOnly": "1409952730536", 
 "timeOnly": "1409953948034", 
 "comments": null}

DateTime有一个默认的Writes实现,它以毫秒为单位输出值。

我想输出的是这样的:

{"id": 123, 
 "dateOnly": "2014-03-08", 
 "timeOnly": "15:24", 
 "comments": ""}

所以我想我需要通过函数调用来处理dateOnly,timeOnly和comments字段值,以便在写出最终JSON值之前得到我想要的内容。

我至少需要一个带有DateTime模式的自定义Writes,如下所示:

def dateTimeWrites(pattern: String): Writes[DateTime] = new Writes[DateTime] {
    def writes(d: DateTime): JsValue = JsString(d.toString(pattern))
}

我无法看到我应该如何将此自定义Writes实现合并到Test Writes实现中,也无法看到如何为两个不同的日期/时间字段指定两种不同的模式。

我也看不到如何为注释发出空字符串而不是null - writeNullable会完全省略注释字段而我不想要。

鉴于经过多次搜索,我似乎找不到任何可以理解的例子,我怀疑自己的方法是错误的。

1 个答案:

答案 0 :(得分:2)

不需要您的自定义Writes[DateTime],该库提供了一个。

val myDateWrites = Writes.jodaDateWrites("x-MM-dd")

val myTimeWrites = Writes.jodaDateWrites("HH:mm")

val emptyStringWrites = Writes[Option[String]](_.map(JsString).getOrElse(JsString("")))

implicit val testWrites: Writes[Test] = (
    (__ \ "id"       ).write[Long]               and
    (__ \ "dateOnly" ).write(myDateWrites)       and
    (__ \ "timeOnly" ).write(myTimeWrites)       and
    (__ \ "comments" ).write(emptyStringWrites)
)(unlift(Test.unapply))

然后你得到:

scala> val test = Test(123, DateTime.now(), DateTime.now(), None)
test: Test = Test(123,2014-09-06T00:27:32.903-06:00,2014-09-06T00:27:32.903-06:00,None)

scala> Json.toJson(test)
res6: play.api.libs.json.JsValue = {"id":123,"dateOnly":"2014-09-06","timeOnly":"00:27","comments":""}

所有这些都在Scaladoc中针对JsPath进行了解释:https://www.playframework.com/documentation/2.2.x/api/scala/index.html#play.api.libs.json.JsPath

如果查看函数定义,您会看到def write[T](implicit w: Writes[T])。当您指定.write[String]时,编译器会在某处找到Writes[String]play.api.libs.json.Writes._)并将其传递给该函数。如果你想提供自己的,只需明确地传递它,就像我上面所做的那样。