这是一个人为的例子来说明这一点。我知道我可以使用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会完全省略注释字段而我不想要。
鉴于经过多次搜索,我似乎找不到任何可以理解的例子,我怀疑自己的方法是错误的。
答案 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._
)并将其传递给该函数。如果你想提供自己的,只需明确地传递它,就像我上面所做的那样。