在 Scala Play 2.4 中使用自定义 Writes 将序列化设置为 json

Serialize set to json with a custom Writes in Scala Play 2.4

我有一个用例,我想将用户实体序列化为 json。此用户实体包含我不想公开的私有字段,例如密码。

当我 return 单个用户时,我正在使用自定义 OWrites 来处理此问题:

val userSafeWrites: OWrites[User] = (
      (__ \ EMAIL_FIELD).write[String] ~
      (__ \ FIRST_NAME_FIELD).write[String] ~
      (__ \ LAST_NAME_FIELD).write[String] ~
      (__ \ PHONE_NUMBER_FIELD).write[Option[String]] ~
      (__ \ ID_FIELD).write[Long]
    )(p => (p.email, p.firstName, p.lastName, p.phoneNumber, p._id.get))

然后我指定 OWrites 而不是使用隐式:

 Ok(Json.toJson(user)(User.userSafeWrites))

不过,我现在要return一个Set[User]

我该怎么做?我需要实施 OWrites[Set[User]] 吗?我可以理解如何做到这一点,如果我要 return 一个带有结果的字段名称的对象,例如:

{
  "users": [{user1}, {user2}]
}

但是,我想 return 只是一个数组,以符合其他端点的输出:

[{user1}, {user2}]

或者我应该将集合中的每个元素映射到 JsObject 并将自定义 OWrites 应用于每个对象?最有效的方法是什么?

我觉得这很简单,我只是个白痴,因为我自己找不到答案。

嗯,就这么简单:

Ok(JsArray(userSet.map(user => Json.toJson(user)(User.userSafeWrites)).toSeq))

在发布问题之前,花了一个多小时谷歌搜索并尝试以最荒谬的方式将其整理出来。 发题一分钟解决

有那么一天... 除非有更好的方法

您正在重新实现可遍历的写入,这无论如何都是微不足道的,但仍然如此。另一种选择是重用 Writes

val users: Set[User] = ???
Json.toJson(users)(Writes.traversableWrites(userSafeWrites))

WritesTraversable的定义如下:

implicit def traversableWrites[A: Writes] = Writes[Traversable[A]] { as =>
  JsArray(as.map(toJson(_)).toSeq)
}

这正是你所做的。

它作为Writes[A]类型的隐式参数,并用它来编写每个成员。您可以显式传递此参数以获得所需的 Writes.

@cchantep 提到的另一个选项是在需要的地方导入隐含的。

例如,有一些默认写入的模型

case class User(num: Int)

object User {
  implicit val writes = Json.writes[User]
}

和另一个具有自定义写入的对象

object OtherWrites {
  implicit val custom: Writes[User] = new Writes[User] {
    override def writes(o: User): JsValue = JsNull
  }
}

在class即客户端

object Client extends App {
  val obj = List(User(1))
  print(Json.toJson(obj))
}

您会得到 [{"num":1}] 打印,因为默认写入存在于隐式范围内,因为它们是在 User.

的伴随对象中定义的

您可以在需要的地方导入自定义写入,来自伴随对象的写入将被覆盖

object Client extends App {
  import test.OtherWrites._
  val obj = List(User(1))
  print(Json.toJson(obj))
}

你得到 [null] 打印出来。