Play Framework 2.1中的Scala到JSON

Play Framework 2.1中的Scala到JSON,json,scala,playframework-2.1,Json,Scala,Playframework 2.1,我试图在2.1RC Play框架中将Scala转换为JSON 我可以执行以下操作并获取JSON: import play.api.libs.json._ val a1=Map("val1"->"a", "val2"->"b") Json.toJSon(a1) 因为a1只是工作正常的Map[String,String] 但如果我有更复杂的东西,比如我有Map[String,Object],那就不起作用了: val a = Map("val1" -> "xxx", "val2"

我试图在2.1RC Play框架中将Scala转换为JSON

我可以执行以下操作并获取JSON:

import play.api.libs.json._

val a1=Map("val1"->"a", "val2"->"b")
Json.toJSon(a1)
因为a1只是工作正常的Map[String,String]

但如果我有更复杂的东西,比如我有Map[String,Object],那就不起作用了:

val a = Map("val1" -> "xxx", "val2"-> List("a", "b", "c"))
Json.toJSon(a1)
>>> error: No Json deserializer found for type scala.collection.immutable.Map[String,Object]
我发现我可以做如下事情:

val a2 = Map("val1" -> Json.toJson("a"), "val2" -> Json.toJson(List("a", "b", "c")))
Json.toJson(a2)
a.map{ case(k,v)=> (k, Json.toJson(v) )}
>>> error: No Json deserializer found for type Object
这就行了

但是我怎样才能在一般情况下做到这一点呢?我想我可以做如下的事情:

val a2 = Map("val1" -> Json.toJson("a"), "val2" -> Json.toJson(List("a", "b", "c")))
Json.toJson(a2)
a.map{ case(k,v)=> (k, Json.toJson(v) )}
>>> error: No Json deserializer found for type Object
但我仍然得到一个错误,它不能被反序列化


其他信息:

toJson可以将映射[String,String]转换为JsValue:

scala> val b = Map( "1" -> "A", "2" -> "B", "3" -> "C", "4" -> "D" )
b: scala.collection.immutable.Map[String,String] = Map(1 -> A, 2 -> B, 3 -> C, 4 -> D)

scala> Json.toJson(b)
res31: play.api.libs.json.JsValue = {"1":"A","2":"B","3":"C","4":"D"}
但是,它无法尝试转换映射[字符串,对象]:

scala> a
res34: scala.collection.immutable.Map[String,Object] = Map(val1 -> xxx, val2 -> List(a, b, c))

scala> Json.toJson(a)
<console>:12: error: No Json deserializer found for type scala.collection.immutable.Map[String,Object]. Try to implement an implicit Writes or Format for this type.
          Json.toJson(a)
implicit val objectMapFormat = new Format[Map[String, Object]] {

  def writes(map: Map[String, Object]): JsValue =
    Json.obj(
      "val1" -> map("val1").asInstanceOf[String],
      "val2" -> map("val2").asInstanceOf[List[String]]
    )

  def reads(jv: JsValue): JsResult[Map[String, Object]] =
    JsSuccess(Map("val1" -> (jv \ "val1").as[String], "val2" -> (jv \ "val2").as[List[String]]))
}
因此,我想知道的是,给定一个Map[String,Object],其中我知道对象值最初都是String或List[String]类型,如何将函数Json.toJson()应用于Map中的所有值并获得一个Map[String,JsValue]

我还发现我可以过滤掉那些纯粹是字符串的值和那些属于List[string]类型的值:

scala> val a1 = a.filter({case(k,v) => v.isInstanceOf[String]})
a1: scala.collection.immutable.Map[String,Object] = Map(val1 -> xxx)

scala> val a2 = a.filter({case(k,v) => v.isInstanceOf[List[String]]})
<console>:11: warning: non-variable type argument String in type List[String] is unchecked since it is eliminated by erasure
   val a2 = a.filter({case(k,v) => v.isInstanceOf[List[String]]})
                                                 ^
a2: scala.collection.immutable.Map[String,Object] = Map(val2 -> List(a, b, c))
scala>vala1=a.filter({case(k,v)=>v.isInstanceOf[String]})
a1:scala.collection.immutable.Map[String,Object]=Map(val1->xxx)
scala>vala2=a.filter({case(k,v)=>v.isInstanceOf[List[String]})
:11:警告:类型列表[String]中的非变量类型参数字符串未选中,因为它已通过擦除消除
vala2=a.filter({case(k,v)=>v.isInstanceOf[List[String]})
^
a2:scala.collection.immutable.Map[String,Object]=Map(val2->List(a,b,c))
List[String]过滤给出了一个警告,但似乎给出了我想要的答案。如果可以应用这两个过滤器,然后对结果的值使用Json.toJson(),并将结果合并,那么这可能会起作用吗

但过滤结果仍然是Map[String,Object]类型,这导致了一个问题:

scala> Json.toJson(a1)
<console>:13: error: No Json deserializer found for type scala.collection.immutable.Map[String,Object]. Try to implement an implicit Writes or Format for this type.
          Json.toJson(a1)
scala>Json.toJson(a1)
:13:错误:找不到scala.collection.immutable.Map[字符串,对象]类型的Json反序列化程序。尝试实现此类型的隐式写入或格式。
toJson(a1)

Play 2.1 JSON API没有为类型
Map[String,Ojbect]
提供序列化程序

为特定类型定义
案例类
格式
,而不是
映射[字符串,对象]

// { "val1" : "xxx", "val2" : ["a", "b", "c"] }
case class Hoge(val1: String, val2: List[String])

implicit val hogeFormat = Json.format[Hoge]
如果您不想创建case类。 以下代码为Map[String,Object]提供JSON序列化程序/反序列化程序:

scala> a
res34: scala.collection.immutable.Map[String,Object] = Map(val1 -> xxx, val2 -> List(a, b, c))

scala> Json.toJson(a)
<console>:12: error: No Json deserializer found for type scala.collection.immutable.Map[String,Object]. Try to implement an implicit Writes or Format for this type.
          Json.toJson(a)
implicit val objectMapFormat = new Format[Map[String, Object]] {

  def writes(map: Map[String, Object]): JsValue =
    Json.obj(
      "val1" -> map("val1").asInstanceOf[String],
      "val2" -> map("val2").asInstanceOf[List[String]]
    )

  def reads(jv: JsValue): JsResult[Map[String, Object]] =
    JsSuccess(Map("val1" -> (jv \ "val1").as[String], "val2" -> (jv \ "val2").as[List[String]]))
}

更动态 示例代码:

  val jv = Json.toJson(Map("val1" -> "xxx", "val2" -> List("a", "b", "c"), "val3" -> "sss", "val4" -> List("d", "e", "f")))
  println(jv)
  val jr = Json.fromJson[Map[String, Object]](jv)
  println(jr.get)
输出:

> {"val1":"xxx","val2":["a","b","c"],"val3":"sss","val4":["d","e","f"]}
> Map(val1 -> xxx, val2 -> List(a, b, c), val3 -> sss, val4 -> List(d, e, f))

谢谢,但我想用一种通用的方式。该示例显示了一个包含两个键值对的映射。可能有许多对的值为String或List[String]。其思想是将该对的值转换为JsValue,然后执行Json.toJson(Map[String,JsValue]),这可以正常工作。我正试图从Map[String,Object]中重新创建一个Map[String,JsValue],我知道该对象的类型总是String或List[String]。@GeorgeHernando OK。我的理解有些含糊不清。你给我看一些输入对象和预期输出JSON的例子?好的。我在描述中添加了更多关于我要做什么的信息。@GeorgeHernando请检查我的示例代码和输出。这就是您想要的吗?这很好,可以满足我的要求,但是我仍然不确定为什么像下面这样的简单映射会失败:val b=a.map{case(k,v)=>(k,Json.toJson(v))};toJson(b)