Unable to convert generic case class to json using “writes”

前端 未结 4 842
时光取名叫无心
时光取名叫无心 2021-02-03 12:01

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 {

  i         


        
相关标签:
4条回答
  • 2021-02-03 12:22

    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].

    0 讨论(0)
  • 2021-02-03 12:30

    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]
    }
    
    0 讨论(0)
  • 2021-02-03 12:38

    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)
        }
      }
    }
    
    0 讨论(0)
  • 2021-02-03 12:41

    maybe you can write something like:

        case class Page(items: JsValue, pageIndex: Int, pageSize: Int, totalCount: Long)
    

    Put the JsValue instead of the Seq[T]

    here is my code example:

        case class ResponseObject(state:Int = 1,data:JsValue)
    
        case class City(id:Int,name:String,sort:String){
          require(id > 0)
        }
    
          def list = Action {
            implicit val cityFormat:Format[City] = Json.format[City]
            implicit val responseFormat=Json.format[ResponseObject]
            Ok(Json.toJson(ResponseObject(data=Json.toJson(City.list)))).as("application/json")
          }
    
    0 讨论(0)
提交回复
热议问题