我有一个用例,我想将一个User实体序列化为json。此用户实体包括我不想公开的私人字段,例如密码。
当我返回单个用户时,我使用自定义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))
但是,我现在要返回Set[User]
。
我该怎么做?我需要实施OWrites[Set[User]]
吗?如果我要返回一个带有结果的字段名称的对象,我可以理解如何做到这一点,例如:
{
"users": [{user1}, {user2}]
}
但是,我想简单地返回一个数组,以便与其他端点的输出一致:
[{user1}, {user2}]
或者我应该将集合的每个元素映射到JsObject并将自定义OWrites应用于每个对象?最有效的方法是什么?
我觉得这很简单,而且我只是因为没有找到答案而成为白痴。
答案 0 :(得分:1)
您正在为可遍历的写入重新实现,但仍然是无关紧要的。另一种选择是重用Writes
val users: Set[User] = ???
Json.toJson(users)(Writes.traversableWrites(userSafeWrites))
Writes
的{{1}}定义如下:
Traversable
这就是你所做的。
它采用implicit def traversableWrites[A: Writes] = Writes[Traversable[A]] { as =>
JsArray(as.map(toJson(_)).toSeq)
}
类型的隐式参数,并使用它来编写每个成员。您可以显式传递此参数以获取所需的Writes[A]
。
@cchantep提到的另一个选项就是在你需要的地方导入你的隐式。
例如,让某些模型具有默认写入
Writes
和自定义写入的另一个对象
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
}
}
由于默认写入存在于隐式作用域中,因此会打印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))
}
。
答案 1 :(得分:0)
嗯,这很简单:
Ok(JsArray(userSet.map(user => Json.toJson(user)(User.userSafeWrites)).toSeq))
在发布问题之前花了一个多小时谷歌搜索并尝试以最荒谬的方式对其进行排序。 在发布问题后的一分钟内解决了这个问题。
有一天...... 除非有更好的方法来做到这一点