Как вы сериализуете карту в JSON в Scala? - PullRequest
21 голосов
/ 08 июня 2011

Итак, у меня есть карта в Scala, например:

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

, и я хочу сериализовать эту структуру в строку JSON, используя lift-json.

Кто-нибудь из вас знает, каксделать это?

Ответы [ 7 ]

33 голосов
/ 24 января 2015

Если вы используете последнюю версию Scala 2.10.x и выше:

println(scala.util.parsing.json.JSONObject(m))
26 голосов
/ 08 июня 2011

Как насчет этого?

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

6 голосов
/ 14 февраля 2017

Вы можете бросить свой собственный довольно легко (да, никаких зависимостей).Он выполняет базовую обработку типов и будет выполнять рекурсию в отличие от 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 )

3 голосов
/ 15 февраля 2017

Вы можете использовать этот простой способ, если вы используете игровую среду:

import play.api.libs.json._

Json.toJson(<your_map>)
1 голос
/ 09 мая 2017

Этот код преобразует множество различных объектов и не требует каких-либо библиотек, кроме встроенного scala.util.parsing.json._. Он не будет правильно обрабатывать крайние случаи, такие как Карты с целыми числами в качестве ключей.

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)
  })
}
0 голосов
/ 18 мая 2017

Дополняя ответ @ Раджа.

Для этих вложенных объектов я локально изменяю класс, чтобы получить желаемый toString() следующим образом:

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

Затем внутри объекта карты я использую этот MList вместо стандартного List. Таким образом, мой map объект печатается нормально, вызывая JSONObject(map).toString().

0 голосов
/ 13 февраля 2017

Подобно решению Einar, вы можете использовать JSONObject из Parser Combinators , чтобы сделать это. Обратите внимание, что это не повторяется, вам нужно сделать это самостоятельно. Библиотека также включает JSONArray, для списка, как структуры данных. Что-то вроде следующего поможет решить проблемы Ноэля по поводу вложенных структур. Этот пример не возвращается к произвольному уровню, но будет обрабатывать значение 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
...