Play Framework 2.4中的Writes[-A]与OWrites[-A],Format[A]与OFormat[A]有何区别及用途?

28
在PlayFramework的Json库中,Writes[-A]和OWrites[-A]有什么区别?我已经使用过Writes[A],但是我无法弄清楚OWrites的目的。同样的问题也适用于Format[A] vs OFormat[A]。
可以在这里的Writes这里的Formats找到源代码。我已经查看了它们,但我无法弄清楚它们在使用上的区别。
1个回答

42
通常你知道编码器总是会产生一个JSON对象(而不是任意的JSON值)。在类型系统中跟踪这个事实使得可以在不必要地跳过通常需要的步骤的情况下处理这样一个编码器的输出。
例如,假设我们有一个简单的类:
class Foo(val name: String, val age: Long)

我们可以这样写一个Writes实例:
import play.api.libs.functional.syntax._
import play.api.libs.json._

implicit val fooWrites: Writes[Foo] = (
  (__ \ 'name').write[String] and (__ \ 'age').write[Long]
)(foo => (foo.name, foo.age))

现在我们可以写下以下内容:
scala> val json = fooWrites.writes(new Foo("McBar", 101))
json: play.api.libs.json.JsValue = {"name":"McBar","age":101}

现在假设出于某种原因,我们想要获取字段名称的列表。我们必须编写类似于以下的代码:
scala> json.as[JsObject].keys
res0: scala.collection.Set[String] = Set(name, age)

不要这样做:
scala> json.keys
<console>:17: error: value keys is not a member of play.api.libs.json.JsValue
              json.keys
                   ^

当然,我们知道`json`始终是一个`JsObject`。问题在于编译器不知道。`OWrites`可以解决这个问题。
implicit val fooWrites: OWrites[Foo] = (
   (__ \ 'name').write[String] and (__ \ 'age').write[Long]
)(foo => (foo.name, foo.age))

然后:
scala> val json = fooWrites.writes(new Foo("McBar", 101))
json: play.api.libs.json.JsObject = {"name":"McBar","age":101}

scala> json.keys
res1: scala.collection.Set[String] = Set(name, age)
writesOWrites 上的输出被静态类型化为 JsObject,因此我们可以使用 .keys 而不需要不安全的 as[JsObject] 转换。
(顺便说一下,我个人不太喜欢在子类中使方法返回类型更具体,而且我在解决这个问题时采取了稍微不同的方法,参考 这里这里。)

所以,你的意思是,如果我知道某个东西是一个Json对象(而不是Json数组),最好实现OWrites而不是Writes,对吗?关于“not personally a fan”中的链接,我找不到“更具体的返回类型”的任何地方,所以我无法理解。你能否进一步解释一下你链接的问题?感谢OWrites的解释 :) - vicaba
1
如果您的用例需要,那么更可取。除了在编译时知道它是JsObject之外,我不知道OWriter是否比普通的Writer提供更多/不同的功能。我认为@Travis所说的“更具体的返回类型”是指OWrites[T] extends Writes[T],其中Writest[T] def writes(in: T): JsValue,而OWrites[T]中相同的方法是def writes(in: T): JsObject,其中JsObjectJsValue的子类。 - goral
@goral,我明白了 Writes vs OWrites 的例子中的思路,但我不理解这里发生了什么:https://dev59.com/E10Z5IYBdhLWcg3wxCuQ#zKygEYcBWogLw_1bdnB1 - vicaba
似乎Travis在书写时也没有。 - goral
除了 implicitly[OWrites[Foo]].writes(foo) 之外,还有其他方法可以访问隐式的 OWrites 吗?Json.toJson(foo) 可以找到一个隐式的 Writes,但如果你的隐式是一个 OWrites,它会将其视为一个 Writes 并将输出作为 JsValue 处理。 - emote_control

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接