Play Framework 2.4 Записывает [-A] против OWrites [-A], Format [A] против OFormat [A]. Цель?

Какая разница между Writes [-A] и OWrites [-A] в библиотеке PlayFramework Json? Я использовал Writes [A], но я не могу понять, что цель OWrites. Тот же вопрос относится к Format [A] vs OFormat [A].

Исходный код можно найти здесь для Writes и здесь для форматов. Я посмотрел на них, но я не могу понять разницу в их обычаях.

Ответ 1

Часто вы знаете, что кодер всегда будет создавать объект 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)

Вывод Writes на OWrites статически вводится как JsObject, поэтому мы можем использовать .keys без небезопасного as[JsObject].

(В качестве побочного примечания я не лично поклонник, который делает типы возвращаемых типов более конкретными в подклассах, и я взял несколько иной подход к решению этой проблемы в circe.)