Play Framework:在验证 JSON 时将字符串转换为数字不起作用

Play Framework: Converting strings to numbers while validating JSON does not work

鉴于以下 JSON...

{
    "ask":"428.00",
    "bid":"424.20"
}

...我需要将 askbid 的值转换为数字:

{
    "ask": 428.00,
    "bid": 424.20
}

正如已经讨论过的 ,我只需要像这样创建一个验证器:

def validate = (
  ((__ \ 'ask).json.update(toNumber)) ~
  ((__ \ 'bid).json.update(toNumber))
).reduce

private def toNumber(implicit reads: Reads[String]) = {
  Reads[JsNumber](js =>
    reads.reads(js).flatMap { value =>
      parse[Double](value) match {
        case Some(number) => JsSuccess(JsNumber(number))
        case _ => JsError(ValidationError("error.number", value))
      }
    }
  )
}

问题是只有最后一个节点 (bid) 被实际转换为数字...结果 JSON 如下所示:

}
    "ask":"428.00",
    "bid":424.20
}

我是不是漏掉了什么?

编辑

仅当 JSON 结构仅包含要转换为数字的字符串时,使用 andThen 才有效...而如果 JSON 结构已包含数字字段,则不会。鉴于以下 JSON [last 已经是数字]:

}
    "ask":"428.00",
    "bid":"424.20",
    "last": 430.05
}

如果我像这样修改我的验证器[将 ~ 替换为 andThen 并删除 reduced]...

def validate = (
  ((__ \ 'ask).json.update(toNumber)) andThen
  ((__ \ 'bid).json.update(toNumber)) andThen
  ((__ \ 'last).json.pickBranch(Reads.of[JsNumber]))
)

...然后在尝试验证上面的 JSON 时出现以下错误:

JsError(List((/bid/last,List(ValidationError(error.path.missing,WrappedArray())))))

查看 the docs,您似乎应该使用 "andThen",而不是“~”。参见 "Case 7"。