玩 JsPath 为 Infinite Double 写

Play JsPath writes for Infinite Double

我正在尝试实现一个编写 Doubles 的函数,它的值可能为 Infinity(JSON 中不存在)。

以下是我正在努力实现的一些示例:

Input: Double.PositiveInfinity
Output:
{
  "positiveInfinty": true,
  "negativeInfinty": false,
  "value": null
}

Input: 12.3
Output:
{
  "positiveInfinty": false,
  "negativeInfinty": false,
  "value": 12.3
}

到目前为止,我已经创建了一个增强的 JsPath class,并添加了名为 writeInfinite:

的函数
case class EnhancedJsPath(jsPath: JsPath) {

    private def infinityObject(pos: Boolean, neg: Boolean, value: Option[Double]): JsObject = Json.obj(
        "positiveInfinity" -> pos,
        "negativeInfinity" -> neg,
        "value" -> value
    )

    def writeInfinite: OWrites[Double] = OWrites[Double] { d =>
        if (d == Double.PositiveInfinity) { infinityObject(true, false, None) }
        else if (d == Double.NegativeInfinity) { infinityObject(false, true, None) }
        else { infinityObject(false, false, Some(d)) }
    }
}

object EnhancedJsPath {
    implicit def jsPathToEnhancedJsPath(jsPath: JsPath): EnhancedJsPath = EnhancedJsPath(jsPath)
}

代码全部编译,这是我正在使用的测试:

case class Dummy(id: String, value: Double)
object Dummy {
    implicit val writes: Writes[Dummy] = (
        (JsPath \ "id").write[String] and
        (JsPath \ "value").writeInfinite
    )(unlift(Dummy.unapply))
}

test("EnhancedJsPath.writesInfinite should set positive infinity property") {

    val d = Dummy("123", Double.PositiveInfinity, Some(Double.PositiveInfinity))
    val result = Json.toJson(d)
    val expected = Json.obj(
      "id" -> "123",
      "value" -> Json.obj(
        "positiveInfinity" -> true,
        "negativeInfinity" -> false,
        "value" -> JsNull
      )
    )

    assert(result == expected)
}

测试失败,因为 result 的值为:

{
    "id": "123",
    "positiveInfinity": true,
    "negativeInfinity": false,
    "value": null
}

而不是:

{
    "id": "123",
    "value": {
        "positiveInfinity": true,
        "negativeInfinity": false,
        "value": null
    }
}

我不知道如何修改我的 writeInfinite 以遵守路径。

看看 JsPath#write[A]JsPath#writeNullable[A] 有帮助:

def write[T](implicit w: Writes[T]): OWrites[T] = Writes.at[T](this)(w)

Writes.at 接受 JsPath,这就是 writewriteNullable 保留调用它们的路径的方式。您需要做的就是用它包装您当前的 writeInfinite 实现,同时传递 jsPath 值:

def writeInfinite: OWrites[Double] = Writes.at(jsPath)(OWrites[Double] { d =>
    if (d == Double.PositiveInfinity) infinityObject(true, false, None)
    else if (d == Double.NegativeInfinity) infinityObject(false, true, None)
    else infinityObject(false, false, Some(d))
})

有效:

scala> Json.toJson(d)
res5: play.api.libs.json.JsValue = {"id":"123","value":{"positiveInfinity":true,"negativeInfinity":false,"value":null}}