玩地图的scala json与列表

时间:2013-07-29 08:18:27

标签: scala playframework

我有两个课程,User&地址。

case class User(
  id: Pk[Long] = NotAssigned,
  name: String = "",
  email: String = "",
  addresses: Seq[Address])

case class Address(
  id: Pk[Long] = NotAssigned,
  userId: Long,
  city: String)

在我的控制器中,我要发送所有用户及其地址,例如Map[User, List[Address]]。我能够使用anorm(mysql)提取它们,但后来我需要将它们作为json发送。你能帮忙解决一下如何实现写入&读取以上Map[User, List[Address]],谢谢。

3 个答案:

答案 0 :(得分:5)

那应该有帮助

import anorm._
import play.api.libs.json._
import play.api.libs.functional.syntax._


case class User(
  id: Pk[Long] = NotAssigned,
  name: String = "",
  email: String = "",
  addresses: Seq[Address])

case class Address(
  id: Pk[Long] = NotAssigned,
  userId: Long,
  city: String)

// Play does not provide Format[Pk[A]], so you need to define it
implicit def pkReads[A](implicit r: Reads[Option[A]]): Reads[Pk[A]] = r.map {  _.map(Id(_)).getOrElse(NotAssigned)  }
implicit def pkWrites[A](implicit w: Writes[Option[A]]): Writes[Pk[A]] =  Writes(id => w.writes(id.toOption))

implicit val addrFormat = Json.format[Address]
implicit val userFormat = Json.format[User]

现在您可以轻松地序列化用户:

val as = Seq(Address(Id(2), 1, "biim"))
val u = User(Id(1), "jto", "jto@foo.bar", as)

scala> Json.toJson(u)
res6: play.api.libs.json.JsValue = {"id":1,"name":"jto","email":"jto@foo.bar","addresses":[{"id":2,"userId":1,"city":"biim"}]}

正如朱利安所说,你不能只序列化Map[User, Seq[Address]]。它只是没有意义,因为User不能成为Json对象中的键。

答案 1 :(得分:4)

您可以通过将Map[User, List[Address]]转换为List[User]来解决此问题,并且JsonWriter将变得易于编写。

类似的东西:

list.map {
  case (user, address) => user.copy(addresses = address.toSeq)
}

答案 2 :(得分:2)

User中的“地址”包含地址,因此您不需要将Map [User,List [Address]]发送回客户端。 Json将是一系列序列化用户对象,地址就是其中的一部分。如果你确实想要发回Map,那么类型Map [String,List [Address]]在Json序列化上下文中更有意义。这是为List [User]生成Json的代码。输出看起来像这样

[
{
    "id": 1,
    "name": "John Doe",
    "email": "john@email.com",
    "addresses": [
        {
            "id": 1001,
            "userId": 1,
            "city": "Chicago"
        },
        {
            "id": 1002,
            "userId": 1,
            "city": "New York"
        }
    ]
},
{
    "id": 2,
    "name": "Jane Doe",
    "email": "jane@email.com",
    "addresses": [
        {
            "id": 1012,
            "userId": 1,
            "city": "Dallas"
        }
    ]
}

以下是您控制器中的代码。它具有Json.toJson使用的隐式Json格式化程序。

      implicit object PkWrites extends Writes[Pk[Long]] {
    def writes(key: Pk[Long]) = Json.toJson(key.toOption)
  }

  implicit object PkReads extends Reads[Pk[Long]] {
    def reads(json: JsValue) = json match {
      case l: JsNumber => JsSuccess(Id(l.value.toLong))
      case _ => JsSuccess(NotAssigned)
    }
  }

  implicit val AddressWrites: Writes[Address] = (
    (JsPath \ "id").write[Pk[Long]] and
      (JsPath \ "userId").write[Long] and
      (JsPath \ "city").write[String]
    )(unlift(Address.unapply))

  implicit val AddressReads: Reads[Address] = (
    (JsPath \ "id").read[Pk[Long]] and
      (JsPath \ "userId").read[Long] and
      (JsPath \ "city").read[String]
    )(Address.apply _)

  implicit val UserWrites: Writes[User] = (
    (JsPath \ "id").write[Pk[Long]] and
      (JsPath \ "name").write[String] and
      (JsPath \ "email").write[String] and
      (JsPath \ "addresses").write[List[Address]]
    )(unlift(User.unapply))

  def makeJson() = Action {
    val johnAddr1 = Address(Id(1001), 1, "Chicago")
    val johnAddr2 = Address(Id(1002), 1, "New York")
    val janeAddr1 = Address(Id(1012), 1, "Dallas")
    val john = User(Id(1), "John Doe", "john@email.com", List(johnAddr1, johnAddr2))
    val jane = User(Id(2), "Jane Doe", "jane@email.com", List(janeAddr1))
    Ok(Json.toJson(List(john, jane)))
    //    Ok(Json.toJson(map))
  }