2011-06-07 6 views
17

Así que tienes un mapa de Scala como esto:¿Cómo serializas un mapa a JSON en Scala?

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

y quiero serializar esta estructura en una cadena JSON usando ascensor-JSON.

¿Alguno de ustedes sabe cómo hacer esto?

+0

esta publicación es útil http://albertech.blogspot.com/2017/02/convert-nested-map-and-list-data.html – jar

Respuesta

24

¿Qué tal esto?

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

de salida:

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

EDIT:

Para una scala.collections.mutable.Map, debe convertirlo primero en un mapa inmutable: .toMap

+5

Cuando cambio el tipo a scala.collections.mutable.Map, la salida se convierte en: [{"_1": "d", "_ 2": "theD"}, {"_ 1": "a", "_ 2 ":" theA "}, {" _ 1 ":" c "," _ 2 ":" theC "}, {" _ 1 ":" b "," _ 2 ":" theB "}, {" _ 1 ":" e "," _ 2 ":" theE "}], lo que me entristece. –

+4

Hay una solución fácil para esto: simplemente llame .toMap en el mapa mutable para obtener un mapa inmutable, y luego las cosas funcionan bien de nuevo. –

+1

Pero, ¿qué ocurre si desea conservar el orden de los elementos en el mapa? Básicamente, ¿cómo json-serializar un LinkedHashMap? Llamar a mapa puede modificar el orden de las entradas. – teo

22

Si está utilizando la última Scala 2.10. x y arriba:

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

Se ha eliminado de Scala 2.11 y superior. – Soid

+1

@Soid parece que todavía está allí: http://www.scala-lang.org/api/2.11.8/scala-parser-combinators/#scala.util.parsing.json.JSONObject – nevets1219

+0

Podría cometer un error en algún lugar . Pero, ¿pudiste usarlo? ¿Qué versión de scala-parser-combinators utilizó (una dependencia completa de maven sería útil)? – Soid

0

Similar a la solución de Einar, puede usar JSONObject desde Parser Combinators para hacer esto. Tenga en cuenta que no se repite, tendrá que hacer esto usted mismo. La biblioteca también incluye JSONArray, para listas como estructuras de datos. Algo como lo siguiente abordará las preocupaciones de Noel sobre las estructuras anidadas. Este ejemplo no se repite a un nivel arbitrario, pero manejará un valor de Lista [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 
4

Puede enrollar el suyo con bastante facilidad (es decir, sin dependencias). Esto lo hace el manejo básico de los tipos y hará recursividad a diferencia JSONObject que fue mencionado:

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

se puede ver en acción al igual que

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

(que es parte de una biblioteca Coinbase GDAX que he escrito , ver util.scala)

2

se puede usar esta forma sencilla si está utilizando marco juego:

import play.api.libs.json._ 

Json.toJson(<your_map>) 
1

Este código convertirá muchos objetos diferentes, y no requiere ninguna biblioteca más allá del incorporado scala.util.parsing.json._. No manejará adecuadamente casos extremos como Mapas con enteros como claves.

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

Complementando la respuesta por @Raja.

Para aquellos objeto anidado, puedo modificar localmente a la clase que tiene mi querido toString() como esta manera:

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

A continuación, dentro del objeto de mapa que utilizan este MList en lugar del estándar List. De esta forma, mi objeto map se imprime bien llamando al JSONObject(map).toString().

Cuestiones relacionadas