开发者

How do you serialize a Map to JSON in Scala?

So I have a Map in Scala like thi开发者_如何学编程s:

val m = Map[String, String](
    "a" -> "theA",
    "b" -> "theB",
    "c" -> "theC",
    "d" -> "theD",
    "e" -> "theE"
)

and I want to serialize this structure into a JSON string using lift-json.

Do any of you know how to do this?


If you are using the latest Scala 2.10.x and above :

println(scala.util.parsing.json.JSONObject(m))


How about this?

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

output:

{"e":"theE","a":"theA","b":"theB","c":"theC","d":"theD"}

EDIT:

For a scala.collections.mutable.Map, you should convert it first to an immutable map: .toMap


You can roll your own pretty easily (yay, no dependencies). This one does basic handling of types and will do recursion unlike JSONObject that was mentioned:

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("\"" , "\\\\\"");
  }
}

You can see it in action like

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

(It's part of a Coinbase GDAX library I've written, see util.scala)


You can use this simple way if you are using play framework:

import play.api.libs.json._

Json.toJson(<your_map>)


This code will convert many different objects, and doesn't require any libraries beyond the built-in the scala.util.parsing.json._. It won't properly handle edge cases like Maps with integers as keys.

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


Similar to Einar's solution, you can use JSONObject from Parser Combinators to do this. Note that it does not recurse, you'll need to do this yourself. The library also includes JSONArray, for list like data structures. Something like the following will address Noel's concerns about nested structures. This example does not recurse to an arbitrary level, but will handle a value of 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


Supplementing the answer by @Raja.

For those nested object, I locally modify the class to have my wanted toString() like this way:

case class MList[T]() extends MutableList[T] { override def toString() = "[" + this.toList.mkString(",") + "]" }

Then inside the Map object, I use this MList instead of the standard List. That way, my map object prints out fine by calling JSONObject(map).toString().

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜