How to write implicit Writes for case class having more than 22 fields

扶醉桌前 提交于 2019-12-11 03:48:42

问题


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
)

For a case class like this, I need to write implicit json de- / serializer. I tried splitting the fields, and had a JSONFormat. But still I need implicit OWrited for using Json.obj(). I tried with play-json-extensions also. Any ideas?


回答1:


There's really 3 avenues for you to explore here:

  1. Write out each class explicitly yourself (yes, tons of boilerplate.)
  2. Do it with Macros or Shapeless.
  3. Use someone's library who already did #2.

I like it when someone else does the work for me. So with that in mind, #3 seems like my preferred solution... And what would you know? Someone else did just that: play-json-derived-codecs. Since it uses Shapeless, it will be able to handle case classses of arbitrary size, not just those constrained by ProductN (1-22, depending on your version of Scala.)




回答2:


We can achieve without using play-json-extensions. Suppose we have a case class of more than 22 fields like below:

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

Now we will split and group the fields into some groups and write formats.

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 

And finally merge all the formats into one format.

 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
    )))

We need to import function syntax like below:

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

Now, play can not serialize/deserialize optional and date fields. So, we need to write implicit formats for optional and date fields like below:

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
    }
  }

That's all we need to write Writes for case classes more than 22 fields.

You can read my article here..



来源:https://stackoverflow.com/questions/42696763/how-to-write-implicit-writes-for-case-class-having-more-than-22-fields

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!