Как написать неявную запись для класса case, имеющего более 22 полей

case class Foo(
  _1:Int,_2:Int,_3:Int,_4:Int,_5:Int,
  _21:Int,_22:Int,_23:Int,_24:Int,_25:Int,
  _31:Int,_32:Int,_33:Int,_34:Int,_35:Int,
  _41:Int,_42:Int,_43:Int,_44:Int,_45:Int,
  _51:Int,_52:Int,_53:Int,_54:Int,_55:Int
)

Для такого класса case мне нужно написать неявный де-/сериализатор json. Я попытался разделить поля и получил JSONFormat. Но все же мне нужен неявный OWrited для использования Json.obj(). Я также пробовал использовать play-json-extensions. Есть идеи?


person sowmiyaksr    schedule 09.03.2017    source источник
comment
Вы пробовали классы значений?   -  person FaigB    schedule 09.03.2017
comment
классы стоимости? Прости. не могли бы вы объяснить мне это?   -  person sowmiyaksr    schedule 09.03.2017
comment
Ознакомьтесь с документацией по адресу docs.scala-lang.org/overviews/core/. значения-classes.html   -  person FaigB    schedule 09.03.2017
comment
Как можно использовать класс значений в этом примере? и как это решит?   -  person sowmiyaksr    schedule 09.03.2017
comment
Я не понимаю, как классы значений решат эту проблему.   -  person wheaties    schedule 09.03.2017


Ответы (2)


Здесь действительно есть 3 направления, которые вы можете изучить:

  1. Напишите каждый класс самостоятельно (да, тонны шаблонов).
  2. Сделайте это с помощью макросов или Shapeless.
  3. Воспользуйтесь чьей-нибудь библиотекой, которая уже сделала #2.

Мне нравится, когда за меня работает кто-то другой. Итак, имея это в виду, № 3 кажется моим предпочтительным решением... И что бы вы знали? Кто-то сделал именно это: play-json-derived-codecs. Поскольку он использует Shapeless, он сможет обрабатывать классы case произвольного размера, а не только те, которые ограничены ProductN (1-22, в зависимости от вашей версии Scala.)

person wheaties    schedule 09.03.2017
comment
+1 за чужую библиотеку. У вас также есть play-json-extensions, который использует макросы для выполнения своей работы. - person vdebergue; 09.03.2017

Мы можем добиться этого без использования play-json-extensions. Предположим, у нас есть класс case из более чем 22 полей, как показано ниже:

case class Foo(
  A: Int,
  B: Option[Int],
  C: String,
  D: Option[String],
  E: Seq[String],
  F: Date
  more fields..
)

Теперь разделим и сгруппируем поля в несколько групп и напишем форматы.

val fooFormat1: OFormat[(Int, Option[Int], String)] =
    ((__ \ "A").format[Long]
      ~ (__ \ "B").format[Option[Long]]
      ~ (__ \ "C").format[Option[Long]]).tupled


val fooFormat2: OFormat[(Option[String], Seq[String], Date)] =
    ((__ \ "D").format[Long]
      ~ (__ \ "E").format[Option[Long]]
      ~ (__ \ "F").format[Option[Long]]).tupled 

И, наконец, объединить все форматы в один формат.

 implicit val fooFormat: Format[Foo] = (fooFormat1 ~ fooFormat2)({
     case ((a, b, c), (d, e, f)) =>
      new Foo(a, b, c, d, e, f)
   }, (foo: Foo) => ((
    foo.A,
    foo.B,
    foo.C
  ), (
      foo.D,
      foo.E,
      foo.F
    )))

Нам нужно импортировать синтаксис функции, как показано ниже:

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

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

implicit object DateFormat extends Format[java.util.Date] {
    val format = new java.text.SimpleDateFormat("yyyy-MM-dd")
    def reads(json: JsValue): JsResult[java.util.Date] = JsSuccess(format.parse(json.as[String]))
    def writes(date: java.util.Date): JsString = JsString(format.format(date))
  }

implicit def optionFormat[T: Format]: Format[Option[T]] = new Format[Option[T]] {
    override def reads(json: JsValue): JsResult[Option[T]] = json.validateOpt[T]

    override def writes(o: Option[T]): JsValue = o match {
      case Some(t) => implicitly[Writes[T]].writes(t)
      case None    => JsNull
    }
  }

Это все, что нам нужно написать Writes для классов case более чем 22 полей.

Вы можете прочитать мою статью здесь..

person Setu Kumar Basak    schedule 08.09.2017