I want to deserialize this json, which represents a rack that is a 5x5 playing field and contains one tile at position (1,2):
{
"rows" : 5,
"cols" : 5,
"tiles" : [ {
"row" : 1,
"col" : 2,
"tile" : {
"number" : 3
}
} ]
}
So my case classes are:
case class Tile(number: Int)
case class Rack(rows: Int, cols: Int, tiles: Map[(Int, Int), Tile])
I tried to write a Reads for the class rack:
implicit val tileWrites = Json.writes[Tile]
implicit val tileReads = Json.reads[Tile]
implicit val reads: Reads[Rack] = (
(__ \ "rows").read[Int] and
(__ \ "cols").read[Int] and
(__ \ "tiles").read[Map[(Int, Int), Tile]]
) (Rack.apply _)
But i got this error:
Error:(50, 26) No Json deserializer found for type Map[(Int, Int),de.htwg.se.rummi.model.model.Tile]. Try to implement an implicit Reads or Format for this type.
(__ \ "tiles").read[Map[(Int, Int), Tile]]
Can someone explain how I write a Reads for Map[(Int, Int), Tile]?
I wouldn't recommend defining a custom Reads
instance for common types like Map
. Instead I would recommend defining a custom type for the tiles and implement a Reads
for that. The advantage is that you can place the Reads
instance in the companion object and the compiler will always find the correct instance without you having to import anything.
case class Tiles(tiles: Map[(Int, Int), Tile])
Now you can define a Reads
instance for Tiles
in the companion object:
import play.api.libs.json._
import play.api.libs.functional.syntax._
object Tiles {
implicit val reads: Reads[Tiles] =
Reads.list {
(
(__ \ "row").read[Int] and
(__ \ "col").read[Int] and
(__ \ "tile").read[Tile]
) { (row, col, tile) => ((row, col), tile) }
}.map(tuples => Tiles(tuples.toMap))
}