Воспроизведение JSON Reads/Writes с однопараметрическими классами case

Это создает Writes для класса case

import play.api.libs.json._
import play.api.libs.functional.syntax._

case class A(a: String, b: String, c: String)
(JsPath.write[String] and
    JsPath.write[String] and
    JsPath.write[String])(unlift(A.unapply))

Это может быть расширено для работы для параметров 2, 3, 4, 5, 6 и т.д.... но не 1.

case class B(a: String)
(JsPath.write[String])(unlift(B.unapply))

Ошибка компилятора:

error: overloaded method value write with alternatives:
  (t: String)(implicit w:  play.api.libs.json.Writes[String])play.api.libs.json.OWrites[play.api.libs.json.JsValue] <and>
  (implicit w: play.api.libs.json.Writes[String])play.api.libs.json.OWrites[String]
  cannot be applied to (B => String)
              (JsPath.write[String])(unlift(B.unapply))
                           ^

Аналогичная проблема возникает при Reads.

Как я могу получить Reads и Writes для кластеров с одним параметром?

Ответы

Ответ 1

Как сказал Тревис:

  • Преобразование существующих Чтений: используйте метод карты
  • Преобразование существующих писем: использование contramap

Однако contramap работает только с Writes, которые производят JsObject. Ваши записи не будут выполняться во время выполнения:

val w = JsPath.write[String].contramap[B](_.a)
scala> w.writes(B("Hello"))
java.lang.RuntimeException: when empty JsPath, expecting JsObject

Вы можете создать Writes "с нуля", используя Writes.apply:

Writes[B](b => JsString(b.a))

Аналогичным образом вы можете создать чтение с помощью Reads.apply.