How to convert Scala Map into JSON String?

2019-03-25 01:11发布

问题:

For example, I have this Map value in Scala:

val m = Map(
    "name" -> "john doe", 
    "age" -> 18, 
    "hasChild" -> true, 
    "childs" -> List(
        Map("name" -> "dorothy", "age" -> 5, "hasChild" -> false),
        Map("name" -> "bill", "age" -> 8, "hasChild" -> false)
    )
)

I want to convert it to its JSON string representation:

{
    "name": "john doe",
    "age": 18,
    "hasChild": true,
    "childs": [
        {
            "name": "dorothy",
            "age": 5,
            "hasChild": false
        },
        {
            "name": "bill",
            "age": 8,
            "hasChild": false
        }
    ]
}

I'm currenly working on Play framework v2.3, but the solution doesn't need to use Play JSON library, although it will be nice if someone can provide both Play and non-Play solution.

This is what I have done so far without success:

// using jackson library
val mapper = new ObjectMapper()
val res = mapper.writeValueAsString(m)
println(res)

Result:

{"empty":false,"traversableAgain":true}

I don't understand why I got that result.

回答1:

As a non play solution, you can consider using json4s which provides a wrapper around jackson and its easy to use. If you are using json4s then you can convert map to json just by using:

write(m)                                        
//> res0: String = {"name":"john doe","age":18,"hasChild":true,"childs":[{"name":"dorothy","age":5,"hasChild":false},{"name":"bill","age":8,"hasChild":false}]}

--Updating to include the full example--

import org.json4s._
import org.json4s.native.Serialization._
import org.json4s.native.Serialization
implicit val formats = Serialization.formats(NoTypeHints)

 val m = Map(
  "name" -> "john doe",
  "age" -> 18,
  "hasChild" -> true,
  "childs" -> List(
    Map("name" -> "dorothy", "age" -> 5, "hasChild" -> false),
    Map("name" -> "bill", "age" -> 8, "hasChild" -> false)))

 write(m)

Output:

 res0: String = {"name":"john doe","age":18,"hasChild":true,"childs":[{"name" 
 :"dorothy","age":5,"hasChild":false},{"name":"bill","age":8,"hasChild":false }]}

Alternative way:

import org.json4s.native.Json
import org.json4s.DefaultFormats

Json(DefaultFormats).write(m)


回答2:

You need to tell jackson how to deal with scala objects: mapper.registerModule(DefaultScalaModule)



回答3:

val mapper = new ObjectMapper()
mapper.writeValueAsString(Map("a" -> 1))

result> {"empty":false,"traversableAgain":true}

==============================

import com.fasterxml.jackson.module.scala.DefaultScalaModule

val mapper = new ObjectMapper()
mapper.registerModule(DefaultScalaModule)
mapper.writeValueAsString(Map("a" -> 1))

result> {"a":1}



回答4:

val mymap = array.map {
  case 1 => ("A", 1)
  case 2 => ("B", 2)
  case 3 => ("C", 3)
}
  .toMap

Using scala.util.parsing.json.JSONObject, you only need 1 line:

import scala.util.parsing.json.JSONObject

JSONObject(mymap).toString()


回答5:

If you're working with a well-defined data model, why not define case classes and use Play JSON macros to handle conversion? i.e.

case class Person(name: String, age: Int, hasChild: Boolean, childs: List[Person])

implicit val fmt = Json.format[Person]

val person = Person(...)

val jsonStr = Json.toJson(person)


回答6:

One thing you can do using the Jackson library is to use a java HashMap object, instead of a Scala one. Then you can basically use the same "without success" code you already wrote.

import org.codehaus.jackson.map.ObjectMapper
val mapper = new ObjectMapper()
val jmap = new java.util.HashMap[String, Int]()
jmap.put("dog", 4)
jmap.put("cat", 1)
// convert to json formatted string
val jstring  = mapper.writeValueAsString(jmap)
println(jstring)

returns

jstring: String = {"dog":4,"cat":1}