Подтвердить что ты не робот

Как вы сериализуете карту в JSON в Scala?

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

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

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

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

4b9b3361

Ответ 1

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

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

EDIT:

Для a scala.collections.mutable.Map вы должны сначала преобразовать его в неизменяемую карту: .toMap

Ответ 2

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

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

Ответ 3

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

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

import play.api.libs.json._

Json.toJson(<your_map>)

Ответ 5

Этот код преобразует много разных объектов и не требует каких-либо библиотек, кроме встроенного 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)
  })
}

Ответ 6

Подобно решению Einar, вы можете использовать JSONObject из Parser Combinators для этого. Обратите внимание, что он не рекурсирует, вам нужно будет сделать это самостоятельно. Библиотека также включает JSONArray, для таких списков, как структуры данных. Что-то вроде следующего будет касаться проблем Ноэля о вложенных структурах. Этот пример не перезаписывается на произвольный уровень, но будет обрабатывать значение Список [Карта [Строка, Любой]].

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