为什么我不能将Map [String,Any]序列化为JSON?

Joã*_*ves 2 json scala playframework

我似乎找不到一种正确的方法来将我的Map序列化为JSON对象,当它具有不同的值类型时,即:

var user: Map[String, Any] = Map("name" -> "1", "id" -> 1)
val json: JsValue = Json.obj(
  "user" -> user
)
Run Code Online (Sandbox Code Playgroud)

生产:

type mismatch;
 found   : Map[String,Any]
 required: play.api.libs.json.Json.JsValueWrapper
Run Code Online (Sandbox Code Playgroud)

或者,如果我使用Map[String,AnyVal],它会产生:

the result type of an implicit conversion must be more specific than AnyVal
Run Code Online (Sandbox Code Playgroud)

但是,如果我使用其中任何一个Map[String,Number]Map[String,String]它有效

我缺少什么,是否有一些我可以调用以在JSON.obj()调用中安全地使用数字和整数的包装器?

nat*_*bbs 5

鉴于您的代码段,您需要执行以下操作:

var user = Map("name" -> "1", "id" -> 1)
var json: JsValue = Json.obj(
    "user" -> Json.toJson(user)
)
Run Code Online (Sandbox Code Playgroud)

将出现的下一个问题是Play无法找到隐式writes类型Map[String, Any].

我建议你Writes为你想要序列化的对象编写自己的.也许如下所示:

case class User(props: Map[String, Any])

implicit val writes: Writes[User] = new Writes[User]{
  override def writes(o: User): JsValue = {
    val propsJs = JsObject(
      o.props.map{kvp =>
        kvp._1 -> (kvp._2 match {
          case x: String => JsString(x)
          case x: Int => JsNumber(x)
          case _ => JsNull // Do whatever you want here.
        })
      }
    )
    JsObject(Map("user" -> propsJs))
  }
}
Run Code Online (Sandbox Code Playgroud)

通过测试:

val u1 = User(Map("name" -> "1", "id" -> 1))

val js = Json.toJson(u1)

out: js: play.api.libs.json.JsValue = {"user":{"name":"1","id":1}}
Run Code Online (Sandbox Code Playgroud)

编辑:

正如评论中指出的那样,执行以下操作可能是有利的(取决于您的用例):

case class User(name: String, id: Int)

implicit val writes = Json.writes[User]
Run Code Online (Sandbox Code Playgroud)

这是一个更具可读性,更好地巩固了a的定义User.有可能你不能这样做,但如果你能(我和其他人)可以提出建议.

  • 我相信使用`case class User(props:Map [String,Any])`令人困惑.为什么不将`User`的实际成员字段指定为`String`,`Int`等,然后根据http://stackoverflow.com/questions/21714825/create-writes-并定义`Writes [User]` -format-的情况下级/? (2认同)