json scala playframework-2.1

Scala a JSON en Play Framework 2.1



playframework-2.1 (1)

Estoy intentando convertir Scala a JSON en el marco de juego 2.1RC.

Puedo hacer lo siguiente y obtener JSON:

import play.api.libs.json._ val a1=Map("val1"->"a", "val2"->"b") Json.toJSon(a1)

Porque a1 es solo Map [String, String] que funciona bien.

Pero si tengo algo más complejo como donde tengo Map [String, Object], eso no funciona:

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]

Descubrí que puedo hacer algo como lo siguiente:

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

Y eso funciona.

Pero, ¿cómo puedo hacer eso de una manera general? Pensé que podía hacer algo como lo siguiente:

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

Pero sigo teniendo el error de que no se puede deserializar.

Información Adicional:

Json.toJson puede convertir un Mapa [String, String] en un 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"}

Pero, falla al intentar convertir un Mapa [Cadena, Objeto]:

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)

Usando el ''consejo'' de esta página de Play Framework para convertir Scala a Json, encontré lo siguiente ( http://www.playframework.org/documentation/2.0.1/ScalaJson ):

Si en lugar de Map [String, Object], hay un Map [String, JsValue], entonces Json.toJson () funcionará:

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

Entonces, lo que me gustaría, es que dado un Mapa [Cadena, Objeto], donde sé que los valores del Objeto eran originalmente de tipo Cadena o Lista [Cadena], cómo aplicar la función Json.toJson () a todos los valores en el mapa y obtener un Mapa [String, JsValue].

También encontré que puedo filtrar aquellos valores que son puramente cadenas y aquellos que son (eran) de tipo Lista [Cadena]:

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

El filtrado de la Lista [Cadena] da una advertencia, pero parece dar la respuesta que quiero. Si los dos filtros pudieran aplicarse y luego Json.toJson () se usara en los valores del resultado, y los resultados combinados, ¿tal vez eso funcionaría?

Pero los resultados filtrados aún son del tipo Mapa [Cadena, Objeto] que causa un problema:

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)


Play 2.1 JSON API no proporciona un serializador para el Tipo de Map[String, Ojbect] .

Defina la case class y el Format para el tipo específico en lugar de Map[String, Object] :

// { "val1" : "xxx", "val2" : ["a", "b", "c"] } case class Hoge(val1: String, val2: List[String]) implicit val hogeFormat = Json.format[Hoge]

Si no quieres crear clase de caso. El siguiente código proporciona el serializador / deserializador JSON para 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]])) }

Mas dinamicamente

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

Código de muestra:

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)

La salida:

> {"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))