如何在 Scala 中将 Map 序列化为 JSON?
Posted
技术标签:
【中文标题】如何在 Scala 中将 Map 序列化为 JSON?【英文标题】:How do you serialize a Map to JSON in Scala? 【发布时间】:2011-09-10 09:54:36 【问题描述】:所以我在 Scala 中有一个这样的地图:
val m = Map[String, String](
"a" -> "theA",
"b" -> "theB",
"c" -> "theC",
"d" -> "theD",
"e" -> "theE"
)
我想使用 lift-json 将此结构序列化为 JSON 字符串。
你们中有人知道怎么做吗?
【问题讨论】:
【参考方案1】:如果您使用的是最新的 Scala 2.10.x 及更高版本:
println(scala.util.parsing.json.JSONObject(m))
【讨论】:
它已从 Scala 2.11 及更高版本中删除。 @Soid 看起来还在那里:scala-lang.org/api/2.11.8/scala-parser-combinators/… 我可能在某处犯了错误。但是你能用吗?您使用了哪个版本的 scala-parser-combinators(完整的 maven 依赖项会有所帮助)? 看起来它没有正确递归到对象中。例如,Map("0" -> 1, "1" -> List(Map("2" -> 3)))
被字符串化为 "0" : 1, "1" : List(Map(2 -> 3))
。
注意,它不会递归,并且会将嵌套对象转换为它们的字符串表示形式!【参考方案2】:
这个怎么样?
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))))
输出:
"e":"theE","a":"theA","b":"theB","c":"theC","d":"theD"
编辑:
对于scala.collections.mutable.Map
,您应该先将其转换为不可变映射:.toMap
【讨论】:
当我将类型更改为 scala.collections.mutable.Map 时,输出变为:["_1":"d","_2":"theD","_1": "a","_2":"theA","_1":"c","_2":"theC","_1":"b","_2":"theB", "_1":"e","_2":"theE"],这让我有点难过。 有一个简单的解决方法 - 只需在可变映射上调用 .toMap 以获取不可变映射,然后一切正常。【参考方案3】:您可以很容易地推出自己的产品(是的,没有依赖关系)。与提到的JSONObject
不同,这个对类型进行基本处理并将进行递归:
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("\"" , "\\\\\"");
你可以看到它的实际效果
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"]]
(它是我编写的 Coinbase GDAX 库的一部分,请参阅 util.scala)
【讨论】:
【参考方案4】:如果你使用 play framework,你可以使用这个简单的方法:
import play.api.libs.json._
Json.toJson(<your_map>)
【讨论】:
【参考方案5】:此代码将转换许多不同的对象,并且不需要内置 scala.util.parsing.json._
之外的任何库。它不能正确处理像使用整数作为键的 Maps 这样的边缘情况。
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)
)
【讨论】:
【参考方案6】:与 Einar 的解决方案类似,您可以使用来自 Parser Combinators 的 JSONObject 来执行此操作。请注意,它不会递归,您需要自己执行此操作。该库还包括 JSONArray,用于类似数据结构的列表。以下内容将解决 Noel 对嵌套结构的担忧。此示例不会递归到任意级别,但会处理 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
【讨论】:
【参考方案7】:补充@Raja 的答案。
对于那些嵌套对象,我在本地修改类以拥有我想要的toString()
,如下所示:
case class MList[T]() extends MutableList[T]
override def toString() = "[" + this.toList.mkString(",") + "]"
然后在 Map 对象中,我使用这个MList
而不是标准的List
。这样,我的map
对象通过调用JSONObject(map).toString()
可以很好地打印出来。
【讨论】:
以上是关于如何在 Scala 中将 Map 序列化为 JSON?的主要内容,如果未能解决你的问题,请参考以下文章