这是我的用例:
外部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)
答案 0 :(得分:4)
调试Reads
时,查看validate[T]
可能出现的验证错误和异常非常有用。您尚未发布案例类,但将格式为xx.xx
的字段反序列化为Int
没有任何意义。致电NumberFormatException
时,您会收到"20.20".toInt
。 Double
可能更有意义,或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 _)
当然,如果lat
或lon
不是数字,则会引发异常。
处理此问题的最佳方法是不要将JSON中的数字格式化为字符串。然后play-json库将为您处理错误。如果无法做到这一点,您可以考虑使用Try
。
(__ \ "lat").readNullable[String].map(_.flatMap(x => Try(x.toDouble).map(Some(_)).getOrElse(None)))