Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Unable to convert generic case class to json using "writes"

I have a class which I want to be able to convert to json:

case class Page[T](items: Seq[T], pageIndex: Int, pageSize: Int, totalCount: Long)

object Page {

  implicit val jsonWriter: Writes[Page[_]] = Json.writes[Page[_]]
}

The error is No apply function found matching unapply parameters

like image 747
Incerteza Avatar asked Jan 27 '14 06:01

Incerteza


3 Answers

You can define Format[Page[T]] for generic case class Page[T] like this:

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

implicit def pageFormat[T: Format]: Format[Page[T]] =
  ((__ \ "items").format[Seq[T]] ~
    (__ \ "pageIndex").format[Int] ~
    (__ \ "pageSize").format[Int] ~
    (__ \ "totalCount").format[Long])(Page.apply, unlift(Page.unapply))

Although this solution requires more typing, it keeps your case class Page[T] clear of implicit parameter list or need to define concrete subclasses of Page[T].

like image 107
Josef Vlach Avatar answered Oct 31 '22 20:10

Josef Vlach


I'd prefer this solution with trait, but in case you do want to make your case class generic you could use one of 2 approaches.

In case you don't have to use Page[_], i.e. you'll always call toJson on Page[Int] or Seq[Page[String]], but not on Page[_] or Seq[Page[_]]:

object Page {
  implicit def pageWriter[T: Writes](): Writes[Page[T]] = Json.writes[Page[T]]
}

In case you have to serialize Page[_]:

case class Page[T](items: Seq[T],
                   pageIndex: Int,
                   pageSize: Int,
                   totalCount: Long)(
      implicit val tWrites: Writes[T])

object Page {
  implicit def pageWriter[T]: Writes[Page[T]] = new Writes[Page[T]] {
    def writes(o: Page[T]): JsValue = {
      implicit val tWrites = o.tWrites
      val writes = Json.writes[Page[T]]
      writes.writes(o)
    }
  }
}
like image 5
senia Avatar answered Oct 31 '22 19:10

senia


I don't think that you can have a generic writer for any type parameter. I propose following:

trait Page[T] {
  val items: Seq[T]
  val pageIndex: Int
  val pageSize: Int
  val totalCount: Long
}

case class IntPage(items: Seq[Int], pageIndex: Int, pageSize: Int, totalCount: Long) extends Page[Int]

object Page {
  implicit def jsonWriter = Json.writes[IntPage]
}
like image 2
Rado Buransky Avatar answered Oct 31 '22 19:10

Rado Buransky