将选项[String]映射到JSON格式化程序中的Option [Int]

时间:2015-01-04 16:55:15

标签: json scala playframework

这是我的用例:

外部JSON

..
lat: "xx.xx",
lng: "xx.xx",
..

我的(工作)读者,原样:

..
(__ \ 'lat).read[Option[String]] ~
(__ \ 'lng).read[Option[String]] ~
..

我想要做的就是将String映射到Int。从逻辑上讲,因为lat&长坐标应该如此表示。

这是我尝试过的,但不起作用:

(__ \ 'lat).read[Option[String]].map(_.map(_.toInt) orElse None)) ~

尝试执行上述操作时我的案例类,否则他们是Option[String]并且工作:

...
lat: Option[Int],
lng: Option[Int],
...

我认为这个问题可能仅仅是语法问题,但任何其他与parens的组合都无济于事。

修改

它编译,但JSON不解析。它根本不构建我的对象。

如果我试试这个:

(__ \ 'lat).read[Option[String]].map(_.toInt)

我收到错误:

value toInt is not a member of Option[String]

然而,在REPL中,这有效:

val stringOpt: Option[String] = Some("10")
stringOpt.map(_.toInt)
res0: Option[Int] = Some(10)

1 个答案:

答案 0 :(得分:4)

调试Reads时,查看validate[T]可能出现的验证错误和异常非常有用。您尚未发布案例类,但将格式为xx.xx的字段反序列化为Int没有任何意义。致电NumberFormatException时,您会收到"20.20".toIntDouble可能更有意义,或BigDecimal

这有效:

case class Location(lat: Option[Double], lon: Option[Double])

implicit val reads: Reads[Location] = (
    (__ \ "lat").readNullable[String].map(_.map(_.toDouble)) and 
    (__ \ "lon").readNullable[String].map(_.map(_.toDouble))
)(Location.apply _)

当然,如果latlon不是数字,则会引发异常。

处理此问题的最佳方法是不要将JSON中的数字格式化为字符串。然后play-json库将为您处理错误。如果无法做到这一点,您可以考虑使用Try

(__ \ "lat").readNullable[String].map(_.flatMap(x => Try(x.toDouble).map(Some(_)).getOrElse(None)))