在 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))
Writes
对Traversable
的定义如下:
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]
打印出来。
我有一个用例,我想将用户实体序列化为 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))
Writes
对Traversable
的定义如下:
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]
打印出来。