我有一个如下所示的案例类:
case class A(name:String,values:List [Any]) 虽然值可以是long或string的列表。
我正在努力实现写作但没有成功。 这是我的代码:
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))
出于某种原因,当我尝试使用以下值编写案例类时:
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 longs:List [Long]
我不确定我做错了什么。任何想法?
谢谢!
答案 0 :(得分:2)
你非常接近,但请记住,当你说List[Any]
时,就类型系统而言,列表值可能是异构的,而@mz指出,泛型类型将被删除。
在这种情况下,我会使用List[Any]
将List[JsValue]
转换为collect
,以丢弃任何不是字符串或长字符的内容:
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
。
答案 1 :(得分:0)
该解决方案的另一个建议是:
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))