#json #scala #serialization #map #lift
#json #scala #сериализация #словарь #поднять
Вопрос:
Итак, у меня есть карта в Scala, подобная этой:
val m = Map[String, String](
"a" -> "theA",
"b" -> "theB",
"c" -> "theC",
"d" -> "theD",
"e" -> "theE"
)
и я хочу сериализовать эту структуру в строку JSON, используя lift-json.
Кто-нибудь из вас знает, как это сделать?
Ответ №1:
Если вы используете последнюю версию Scala 2.10.x и выше :
println(scala.util.parsing.json.JSONObject(m))
Комментарии:
1. Это было удалено из Scala 2.11 и выше.
2. @Soid выглядит так, как будто он все еще там : scala-lang.org/api/2.11.8/scala-parser-combinators /…
3. Возможно, я где-то допустил ошибку. Но смогли ли вы ее использовать? Какую версию scala-parser-combinators вы использовали (была бы полезна полная зависимость от maven)?
4. Похоже, что он неправильно преобразуется в объект. Например,
Map("0" -> 1, "1" -> List(Map("2" -> 3)))
имеет строковый формат{"0" : 1, "1" : List(Map(2 -> 3))}
.5. Будьте осторожны, это не повторяет, а преобразует вложенные объекты в их строковое представление!
Ответ №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
Комментарии:
1. Когда я меняю тип на scala.collections.mutable. Карта, результат становится: [{«_1″:»d»,»_2″:»theD»},{«_1″:»a»,»_2″:»theA»},{«_1″:»c»,»_2″:»theC»},{«_1″:»b»,»_2″:»theB»},{«_1″:»e»,»_2″:»theE»}] , что делает меня немного грустным.
2. Для этого есть простое решение — просто вызовите . Чтобы получить неизменяемую карту, щелкните по изменяемой карте, и тогда все снова будет работать нормально.
Ответ №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._
. Он не будет должным образом обрабатывать граничные случаи, такие как карты с целыми числами в качестве ключей.
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:
Аналогично решению Эйнара, вы можете использовать JSONObject из Parser Combinators для этого. Обратите внимание, что это не повторяется, вам нужно будет сделать это самостоятельно. Библиотека также включает JSONArray для list-подобных структур данных. Что-то вроде следующего решит проблемы Ноэля по поводу вложенных структур. Этот пример не повторяется до произвольного уровня, но будет обрабатывать значение 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()
.