【问题标题】:How to process object field values before writing to JSON when using combinators使用组合器时如何在写入 JSON 之前处理对象字段值
【发布时间】:2014-10-31 02:08:41
【问题描述】:

这是一个人为的例子来说明这一点。我知道我可以在这里使用 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))

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

这将输出如下内容:

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

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

我想输出的是这样的:

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

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

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

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

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

我也看不到如何为 cmets 发出空字符串而不是 null - writeNullable 会完全省略 cmets 字段,我不希望这样。

鉴于经过大量搜索后,我似乎无法找到任何可以理解的示例来说明我正在尝试做的事情,我怀疑我的方法是错误的。

【问题讨论】:

    标签: scala playframework playframework-2.0 playframework-2.3


    【解决方案1】:

    不需要你自定义的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":""}
    

    所有这些都在 JsPath 的 Scaladoc 中进行了解释: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._)并将其传递给该函数。如果您想提供自己的,只需明确地传递它,就像我在上面所做的那样。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-12-13
      • 2020-03-30
      • 1970-01-01
      • 1970-01-01
      • 2016-11-02
      • 1970-01-01
      • 2011-06-22
      • 1970-01-01
      相关资源
      最近更新 更多