玩 - 尝试实现写入列表[任何]

时间:2016-03-07 00:07:30

标签: json scala playframework playframework-2.0

我有一个如下所示的案例类:

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]

我不确定我做错了什么。任何想法?

谢谢!

2 个答案:

答案 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))