Play Framework Scala format large JSON (No unapply

2020-03-18 03:28发布

问题:

I need to receive a big JSON on my server (more than 22 fields). I have a case class with a lot of fields:

case class Filters(objectType: Option[String] = None,
     deal: Option[String] = None,
     roomsCount: Option[String] = None,
     region: Option[Int] = None,
     district: Option[Int] = None,
     direction: Option[Int] = None
     ...
)

And JSON format function in controller:

implicit val filtersFormat = Json.format[Filters]

At compilation I have error:

[error] WebSockets.scala:18: No unapply or unapplySeq function found
[error]   implicit val filtersFormat = Json.format[Filters]
[error]                                          ^

Is there a way to solve the problem without breaking JSON to small parts?

回答1:

I did it this way:

case class Filters(part1: Part1, part2: Part2, ...)

case class Part1(
    field1: Field1,
    field2: Field2,
    ...
    field10: Field10,
)

object Part1 {
    implicit val part1Format = Json.format[Part1]
}

...

object Filters {
    implicit val filtersReads = (
        JsPath.read[Part1] and
        JsPath.read[Part2] and
        ...
    )(Filters.apply _)

    implicit val filtersWrites = (
        JsPath.write[Part1] and
        JsPath.write[Part2] and
        ...
    )(unlift(Filters.unapply))
}


回答2:

I had the same pb and find a solution by using

Jsonx.formatCaseClass[Filters]

The explication can be found https://harrylaou.com/playframework/bigjson/



回答3:

It is also the option to do it manually, and not with format, reads or writes:

implicit object JsFormatter extends Format[Filter] {

  private val tagField1 = "field1"
  private val tagField2 = "field2"
  private val tagField3 = "field3"
                ...
  private val tagFieldN = "fieldN"   // N > 22

  override def reads(json: JsValue): JsResult[Filter] = JsSuccess(
    Filter(
      (json \ tagField1).as[Long],
      (json \ tagField2).as[Int],
      (json \ tagField3).as[String],
                  ...
      (json \ tagFieldn).as[Boolean]
    ) 
  )

  override def writes(filter: Filter): JsValue = Json.obj(
    tagField1 -> filter.field1,
    tagField2 -> filter.field2,
    tagField3 -> filter.field3,
              ...
    tagFieldN -> filter.fieldN
  )
}

We have many case classes that are passed from 22 columns and all work correctly without separate them into pieces.