为什么可以';我是否将Map[String,Any]序列化为JSON?

为什么可以';我是否将Map[String,Any]序列化为JSON?,json,scala,playframework,Json,Scala,Playframework,我似乎找不到将映射序列化为JSON对象的正确方法,因为它的值具有不同的类型,例如: var user: Map[String, Any] = Map("name" -> "1", "id" -> 1) val json: JsValue = Json.obj( "user" -> user ) 产生: type mismatch; found : Map[String,Any] required: play.api.libs.json.Json.JsValueWr

我似乎找不到将映射序列化为JSON对象的正确方法,因为它的值具有不同的类型,例如:

var user: Map[String, Any] = Map("name" -> "1", "id" -> 1)
val json: JsValue = Json.obj(
  "user" -> user
)
产生:

type mismatch;
 found   : Map[String,Any]
 required: play.api.libs.json.Json.JsValueWrapper
the result type of an implicit conversion must be more specific than AnyVal
或者,如果我改为使用
Map[String,AnyVal]
,它将生成:

the result type of an implicit conversion must be more specific than AnyVal
但是如果我使用
Map[String,Number]
Map[String,String]
这两种方法中的任何一种,它都可以工作


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

给定您的代码片段,您需要执行以下操作:

var user = Map("name" -> "1", "id" -> 1)
var json: JsValue = Json.obj(
    "user" -> Json.toJson(user)
)
case class User(name: String, id: Int)

implicit val writes = Json.writes[User]
接下来将出现的问题是Play找不到类型
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))
  }
}
通过测试:

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}}
编辑:

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

var user = Map("name" -> "1", "id" -> 1)
var json: JsValue = Json.obj(
    "user" -> Json.toJson(user)
)
case class User(name: String, id: Int)

implicit val writes = Json.writes[User]

这是一种更具可读性的方法,可以更好地巩固
用户的定义。您可能无法做到这一点,但如果可以的话,我(和其他人)会建议您这样做。

我认为使用
案例类用户(props:Map[String,Any])
会令人困惑。为什么不将
User
的实际成员字段指定为
String
Int
等,然后定义一个
Writes[User]
per?@KevinMeredith我同意你的看法。OP被要求序列化映射[字符串,任意]。我会更新上述建议。谢谢。另外,我建议阅读特拉维斯·布朗的这篇有帮助的解释。