J'ai donc une carte en Scala comme celle-ci:
val m = Map[String, String](
"a" -> "theA",
"b" -> "theB",
"c" -> "theC",
"d" -> "theD",
"e" -> "theE"
)
et je veux sérialiser cette structure dans une chaîne JSON en utilisant lift-json.
Est-ce que l'un de vous sait comment faire cela?
Que dis-tu de ça?
implicit val formats = net.liftweb.json.DefaultFormats
import net.liftweb.json.JsonAST._
import net.liftweb.json.Extraction._
import net.liftweb.json.Printer._
val m = Map[String, String](
"a" -> "theA",
"b" -> "theB",
"c" -> "theC",
"d" -> "theD",
"e" -> "theE"
)
println(compact(render(decompose(m))))
sortie:
{"e":"theE","a":"theA","b":"theB","c":"theC","d":"theD"}
MODIFIER:
Pour un scala.collections.mutable.Map
, vous devez d'abord le convertir en une carte immuable: .toMap
Si vous utilisez les dernières versions de Scala 2.10.x et supérieures:
println(scala.util.parsing.json.JSONObject(m))
Vous pouvez rouler le vôtre assez facilement (oui, pas de dépendances). Celui-ci gère les types de base et fera la récursivité contrairement à JSONObject
qui a été mentionné:
import scala.collection.mutable.ListBuffer
object JsonConverter {
def toJson(o: Any) : String = {
var json = new ListBuffer[String]()
o match {
case m: Map[_,_] => {
for ( (k,v) <- m ) {
var key = escape(k.asInstanceOf[String])
v match {
case a: Map[_,_] => json += "\"" + key + "\":" + toJson(a)
case a: List[_] => json += "\"" + key + "\":" + toJson(a)
case a: Int => json += "\"" + key + "\":" + a
case a: Boolean => json += "\"" + key + "\":" + a
case a: String => json += "\"" + key + "\":\"" + escape(a) + "\""
case _ => ;
}
}
}
case m: List[_] => {
var list = new ListBuffer[String]()
for ( el <- m ) {
el match {
case a: Map[_,_] => list += toJson(a)
case a: List[_] => list += toJson(a)
case a: Int => list += a.toString()
case a: Boolean => list += a.toString()
case a: String => list += "\"" + escape(a) + "\""
case _ => ;
}
}
return "[" + list.mkString(",") + "]"
}
case _ => ;
}
return "{" + json.mkString(",") + "}"
}
private def escape(s: String) : String = {
return s.replaceAll("\"" , "\\\\\"");
}
}
Vous pouvez le voir en action comme
println(JsonConverter.toJson(
Map("a"-> 1,
"b" -> Map(
"nes\"ted" -> "yeah{\"some\":true"),
"c" -> List(
1,
2,
"3",
List(
true,
false,
true,
Map(
"1"->"two",
"3"->"four"
)
)
)
)
)
)
{"a":1,"b":{"nes\"ted":"yeah{\"some\":true"},"c":[1,2,"3",[true,false,true,{"1":"two","3":"four"}]]}
(Il fait partie d'une bibliothèque Coinbase GDAX que j'ai écrite, voir util.scala )
Vous pouvez utiliser ce moyen simple si vous utilisez un cadre de jeu:
import play.api.libs.json._
Json.toJson(<your_map>)
Ce code convertira de nombreux objets différents et ne nécessite aucune bibliothèque au-delà du scala.util.parsing.json._
intégré. Il ne gérera pas correctement les cas Edge tels que les cartes avec des nombres entiers comme clés.
import scala.util.parsing.json.{JSONArray, JSONObject}
def toJson(arr: List[Any]): JSONArray = {
JSONArray(arr.map {
case (innerMap: Map[String, Any]) => toJson(innerMap)
case (innerArray: List[Any]) => toJson(innerArray)
case (other) => other
})
}
def toJson(map: Map[String, Any]): JSONObject = {
JSONObject(map.map {
case (key, innerMap: Map[String, Any]) =>
(key, toJson(innerMap))
case (key, innerArray: List[Any]) =>
(key, toJson(innerArray))
case (key, other) =>
(key, other)
})
}
Semblable à la solution d'Einar, vous pouvez utiliser JSONObject à partir de Combinators Parser pour le faire. Notez qu'il ne recurse pas, vous devrez le faire vous-même. La bibliothèque comprend également JSONArray, une liste comme les structures de données. Quelque chose comme ce qui suit va répondre aux préoccupations de Noel concernant les structures imbriquées. Cet exemple ne renvoie pas à un niveau arbitraire, mais gérera une valeur de List [Map [String, Any]] .
import scala.util.parsing.json.{JSONArray, JSONObject}
def toJson(m : Map[String, Any]): String = JSONObject(
m.mapValues {
case mp: Map[String, Any] => JSONObject(mp)
case lm: List[Map[String, Any]] => JSONArray(lm.map(JSONObject(_)))
case x => x
}
).toString
Complétant la réponse de @Raja.
Pour ces objets imbriqués, je modifie localement la classe pour que ma toString()
souhaitée se présente comme suit:
case class MList[T]() extends MutableList[T] {
override def toString() = "[" + this.toList.mkString(",") + "]"
}
Ensuite, à l'intérieur de l'objet Map, j'utilise cette MList
au lieu de la List
standard. De cette façon, mon objet map
s'imprime correctement en appelant JSONObject(map).toString()
.