play - 尝试实现 Writes to List[Any]
play - try to implements Writes to List[Any]
我有一个案例 class 看起来像这样:
case class A(名称:字符串,值:列表[任意])
虽然值可以是长列表或字符串列表。
我正在尝试执行写入但没有成功。
这是我的代码:
implicit val myWrites: Writes[A] = (
(JsPath \ "name").write[String] and
(JsPath \ "values").write[JsArray].contramap[List[Any]](
(list: List[Any]) => list match{
case longs: List[Long] => JsArray(longs.map(l => JsNumber(l)))
case strings: List[String] => JsArray(strings.map(s => JsString(s)))
})
) (unlift(A.unapply))
出于某种原因,当我尝试使用以下值编写案例 class 时:
A("name", List("val1", "val2"))
我得到以下异常:
java.lang.String cannot be cast to java.lang.Long
java.lang.ClassCastException: java.lang.String cannot be cast to
java.lang.Long
at scala.runtime.BoxesRunTime.unboxToLong(BoxesRunTime.java:105)
它在第一个 case 行失败:case longs: List[Long]
我不确定我做错了什么。有什么想法吗?
谢谢!
你很接近,但请记住,当你说 List[Any]
时,这意味着就类型系统而言,列表值可以是异构的,正如@m-z 指出的那样,泛型类型将被删除。
在这种情况下,我会使用 collect
将 List[Any]
转换为 List[JsValue]
以丢弃任何非字符串或长整数的内容:
case class A(name: String, values: List[Any])
implicit val myWrites: Writes[A] = (
(JsPath \ "name").write[String] and
(JsPath \ "values").write[List[JsValue]].contramap[List[Any]](
_.collect {
case str: String => JsString(str)
case long: Long => JsNumber(long)
})
)(unlift(A.unapply))
我最近不得不自己做一些类似的事情来处理接受异构 JSON 数组的 Web 服务,但通常最好避免在 Scala 级别使用 Any
。
解决方案的另一个建议:
implicit val myWrites: Writes[A] = (
(JsPath \ "name").write[String] and
(JsPath \ "values").write[JsArray].contramap[List[Any]](
case l if l.isEmpty => JsArray(Seq())
case list@List(_: Long, _*) => JsArray(list.map(l => JsNumber(l.asInstanceOf[Long])))
case list@List(_: String, _*) => JsArray(list.map(s => JsString(s.asInstanceOf[String])))
) (unlift(A.unapply))
我有一个案例 class 看起来像这样:
case class A(名称:字符串,值:列表[任意]) 虽然值可以是长列表或字符串列表。
我正在尝试执行写入但没有成功。 这是我的代码:
implicit val myWrites: Writes[A] = (
(JsPath \ "name").write[String] and
(JsPath \ "values").write[JsArray].contramap[List[Any]](
(list: List[Any]) => list match{
case longs: List[Long] => JsArray(longs.map(l => JsNumber(l)))
case strings: List[String] => JsArray(strings.map(s => JsString(s)))
})
) (unlift(A.unapply))
出于某种原因,当我尝试使用以下值编写案例 class 时:
A("name", List("val1", "val2"))
我得到以下异常:
java.lang.String cannot be cast to java.lang.Long
java.lang.ClassCastException: java.lang.String cannot be cast to
java.lang.Long
at scala.runtime.BoxesRunTime.unboxToLong(BoxesRunTime.java:105)
它在第一个 case 行失败:case longs: List[Long]
我不确定我做错了什么。有什么想法吗?
谢谢!
你很接近,但请记住,当你说 List[Any]
时,这意味着就类型系统而言,列表值可以是异构的,正如@m-z 指出的那样,泛型类型将被删除。
在这种情况下,我会使用 collect
将 List[Any]
转换为 List[JsValue]
以丢弃任何非字符串或长整数的内容:
case class A(name: String, values: List[Any])
implicit val myWrites: Writes[A] = (
(JsPath \ "name").write[String] and
(JsPath \ "values").write[List[JsValue]].contramap[List[Any]](
_.collect {
case str: String => JsString(str)
case long: Long => JsNumber(long)
})
)(unlift(A.unapply))
我最近不得不自己做一些类似的事情来处理接受异构 JSON 数组的 Web 服务,但通常最好避免在 Scala 级别使用 Any
。
解决方案的另一个建议:
implicit val myWrites: Writes[A] = (
(JsPath \ "name").write[String] and
(JsPath \ "values").write[JsArray].contramap[List[Any]](
case l if l.isEmpty => JsArray(Seq())
case list@List(_: Long, _*) => JsArray(list.map(l => JsNumber(l.asInstanceOf[Long])))
case list@List(_: String, _*) => JsArray(list.map(s => JsString(s.asInstanceOf[String])))
) (unlift(A.unapply))