简体   繁体   中英

Play Scala JSON Writes & Inheritance

//Item.scala

package model
trait Item {val id: String}

class MItem(override val id: String, val name: String) extends Item

class DItem(override val id: String, override val name: String, val name2: String)
  extends MItem(valid, name, name2)

object ItemWrites {

  implicit  val MItemWrites = new Writes[MItem] {
    def writes(dItem: MItem) = Json.obj(
      "id" -> mItem.id,
      "name" -> mItem.name
    )
  }

  implicit  val DItemWrites = new Writes[DItem] {
    def writes(dItem: DItem) = Json.obj(
      "id" -> dItem.id,
      "name" -> dItem.name,
      "name2" -> dItem.name2
    )
  }

}

//Response.scala

package model
import ItemWrites.MItemWrites
import ItemWRites.DItemWrites

trait Response {
  val title : String,
  val items : Seq[Item],
}

case class MResponse(title: String, items: Seq[MItem]) extends Response

case class DResponse(title: String, items: Seq[DItem]) extends Response

object ResponseWrites  {

  implicit val mResponseWrite = new Writes[MResponse] {

    def writes(mResponse: MResponse) = Json.obj(
      "title" -> mResponse.title,
      "items" -> mResponse.items
    )
  }

  implicit val dResponseWrite = new Writes[DResponse] {

    def writes(dResponse: DResponse) = Json.obj(
      "title" -> dResponse.title,
      "items" -> dResponse.items // **compile time error**
    )
  }

}

I get compile time error on line dResponse.items.

> [error]  Note: implicit value dtcTopicPageResponseWrite is not
> applicable here because it comes after the application point and it
> lacks an explicit result type
> [error] "items" -> dResponse.items

Seems that this is happening as DItem inherits form MItem and the compile is getting confused between subclass and super class. How do i get around this.

I was able to get your code compiling in Scala 2.11, Play 2.5.x by explicitly stating the types of the Writes you've declared in ItemWrites - namely:

object ItemWrites {

  implicit val MItemWrites:Writes[MItem] = new Writes[MItem] {
    def writes(mItem: MItem) = Json.obj(
      "id" -> mItem.id,
      "name" -> mItem.name
    )
  }

  implicit val DItemWrites:Writes[DItem] = new Writes[DItem] {
    def writes(dItem: DItem) = Json.obj(
      "id" -> dItem.id,
      "name" -> dItem.name,
      "name2" -> dItem.name2
    )
  }
}

Once I did that, Scala was able to find out which implicit was right and away it went.

You should explicitly set which Writer[T] is going to be used because they use inheritance. I didn't test the code below but it should compile and work;

implicit val dResponseWrite = new Writes[DResponse] {

    import ItemWrites.DItemWrites

    def writes(dResponse: DResponse) = Json.obj(
      "title" -> dResponse.title,
      "items" -> Json.toJson(dResponse.items) // **compile time error**
    )
  }

I think it's better for you to have a Writes for the super type Item that will just do match case to check it's type and do toJson. Don't forget to have it implicitly imported

object ItemWrites {

  implicit  val MItemWrites = new Writes[MItem] {
    def writes(dItem: MItem) = Json.obj(
      "id" -> mItem.id,
      "name" -> mItem.name
    )
  }

  implicit  val DItemWrites = new Writes[DItem] {
    def writes(dItem: DItem) = Json.obj(
      "id" -> dItem.id,
      "name" -> dItem.name,
      "name2" -> dItem.name2
    )
  }

  implicit  val ItemWrites = new Writes[Item] {
    def writes(item: Item) = item match {
     case i: DItem => i.toJson //code for converting DItem to Json
     case i: MItem => i.toJson //code to convert MItem to Json
     case _ => throws new RuntimeException("Unsupported Type.")
   }
  }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM