在Play Framework 2.1中将Scala转换为JSON [英] Scala to JSON in Play Framework 2.1

查看:78
本文介绍了在Play Framework 2.1中将Scala转换为JSON的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试在2.1RC Play框架中将Scala转换为JSON.

I'm trying to convert Scala to JSON in the 2.1RC Play Framework.

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

I can do the following and get JSON:

import play.api.libs.json._

val a1=Map("val1"->"a", "val2"->"b")
Json.toJSon(a1)

因为a1只是可以正常工作的Map [String,String].

Because a1 is just Map[String,String] that works OK.

但是如果我有一些更复杂的东西,例如Map [String,Object],那是行不通的:

But if I have something more complex like where I have Map[String,Object], that doesn't work:

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]

我发现我可以做以下事情:

I found that I can do something like the following:

val a2 = Map("val1" -> Json.toJson("a"), "val2" -> Json.toJson(List("a", "b", "c")))
Json.toJson(a2)

那行得通.

但是我该怎么做呢?我以为我可以做以下事情:

But how can I do that in a general way? I thought that I could do something like the following:

a.map{ case(k,v)=> (k, Json.toJson(v) )}
>>> error: No Json deserializer found for type Object

但是我仍然收到一个无法反序列化的错误

But I still get an error that it can't be deserialized

其他信息:

Json.toJson可以将Map [String,String]转换为JsValue:

Json.toJson can convert a Map[String, String] to a 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"}

但是,它无法尝试转换Map [String,Object]:

But, it fails in trying to convert a Map[String, Object]:

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)

使用此Play框架页面上的提示"将Scala转换为Json时,我发现了以下内容( http: //www.playframework.org/documentation/2.0.1/ScalaJson ):

Using the 'hint' from this Play Framework page on converting Scala to Json, I found the following (http://www.playframework.org/documentation/2.0.1/ScalaJson):

如果不是Map [String,Object],而是Map [String,JsValue],则Json.toJson()将起作用:

If instead of Map[String, Object], there is a Map[String, JsValue], then Json.toJson() will work:

scala> val c = Map("aa" -> Json.toJson("xxxx"), "bb" -> Json.toJson( List("11", "22", "33") ) )
c: scala.collection.immutable.Map[String,play.api.libs.json.JsValue] = Map(aa -> "xxxx", bb -> ["11","22","33"])

scala> Json.toJson(c)
res36: play.api.libs.json.JsValue = {"aa":"xxxx","bb":["11","22","33"]}

所以,我想要的是给定Map [String,Object],我知道Object值最初都是String或List [String]类型的,如何应用函数Json.toJson()到地图中的所有值,并获取Map [String,JsValue].

So, what I would like, is that given a Map[String, Object], where I know that the Object values were all originally of type String or List[String], how to apply the function Json.toJson() to the all the values in the map and get a Map[String, JsValue].

我还发现,我可以过滤掉纯字符串形式的值和List [String]类型的值:

I also found that I can filter out those values that are purely string and those that are (were) of type 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))

List [String]过滤给出警告,但似乎给出了我想要的答案.如果可以应用这两个过滤器,然后将Json.toJson()用于结果的值,然后将结果组合在一起,也许行得通吗?

The List[String] filtering gives a warning, but seems to give the answer I want. If the two filters could be applied and then Json.toJson() used on the values of the result, and the results combined, maybe that would work?

但是过滤后的结果仍然是Map [String,Object]类型,这会导致问题:

But the filtered results are still of type Map[String, Object] which causes a problem:

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)

推荐答案

播放2.1 JSON API没有为类型Map[String, Ojbect]提供序列化器.

Play 2.1 JSON API does not provide a serializer for the Type Map[String, Ojbect].

为特定类型而不是Map[String, Object]定义case classFormat:

Define case class and Format for the specific type instead of Map[String, Object]:

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

implicit val hogeFormat = Json.format[Hoge]

如果您不想创建案例类. 以下代码为Map [String,Object]提供JSON序列化器/反序列化器:

If you don't want to create case class. The following code provides JSON serializer/deserializer for Map[String, Object]:

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]]))
}


更动态

import play.api.libs.json._
import play.api.libs.json.Reads._
import play.api.libs.json.Json.JsValueWrapper

implicit val objectMapFormat = new Format[Map[String, Object]] {

  def writes(map: Map[String, Object]): JsValue = 
    Json.obj(map.map{case (s, o) =>
      val ret:(String, JsValueWrapper) = o match {
        case _:String => s -> JsString(o.asInstanceOf[String])
        case _ => s -> JsArray(o.asInstanceOf[List[String]].map(JsString(_)))
      }
      ret
    }.toSeq:_*)


  def reads(jv: JsValue): JsResult[Map[String, Object]] =
    JsSuccess(jv.as[Map[String, JsValue]].map{case (k, v) =>
      k -> (v match {
        case s:JsString => s.as[String]
        case l => l.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))

这篇关于在Play Framework 2.1中将Scala转换为JSON的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆