Reputation: 1197
case class Apple(id:String, name:String)
case class Fruit(id:String,ftype:String)
case class Basket(b:Map[Fruit,Apple])
How to define the play implicits as the below definition are not enough.
implicit val format: Format[Fruit] = Json.format
implicit val format: Format[Apple] = Json.format
This isn't working :
implicit val format: Format[Basket] = Json.format
Upvotes: 0
Views: 88
Reputation: 14803
The formatter are ok, but they only work for Case Classes.
So all you have to do is to adjust them:
case class Apple(id:String, name:String)
case class Fruit(id:String,ftype:String)
case class Basket(b:Map[Fruit,Apple])
Update
Ok there is another problem. JSON has a restriction that the Key of a Map must be a String.
See my answer here: https://stackoverflow.com/a/53896463/2750966
Ok here an example for Play < 2.8:
implicit val formata: Format[Apple] = Json.format
implicit val mapReads: Reads[Map[Fruit, Apple]] = (jv: JsValue) =>
JsSuccess(jv.as[Map[String, Apple]].map { case (k, v) =>
(k.split("::").toList match {
case id :: ftype :: _ => Fruit(id, ftype)
case other => throw new IllegalArgumentException(s"Unexpected Fruit Key $other")
}) -> v
})
implicit val mapWrites: Writes[Map[Fruit, Apple]] = (map: Map[Fruit, Apple]) =>
Json.toJson(map.map { case (fruit, o) =>
s"${fruit.id}::${fruit.ftype}" -> o
})
implicit val jsonMapFormat: Format[Map[Fruit, Apple]] = Format(mapReads, mapWrites)
implicit val formatb: Format[Basket] = Json.format
With this example Data it works:
val basket = Basket(Map(Fruit("12A", "granate") -> Apple("A11", "The Super Apple"),
Fruit("22A", "gala") -> Apple("A21", "The Gala Premium Apple")))
val json = Json.toJson(basket) // >> {"b":{"12A::granate":{"id":"A11","name":"The Super Apple"},"22A::gala":{"id":"A21","name":"The Gala Premium Apple"}}}
json.as[Basket] // >> Basket(Map(Fruit(12A,granate) -> Apple(A11,The Super Apple), Fruit(22A,gala) -> Apple(A21,The Gala Premium Apple)))
Here the Scalafiddle
Upvotes: 2
Reputation: 4608
Here is a possible implementation using Play JSON 2.8:
import play.api.libs.json._
case class Apple(id:String, name:String)
case class Fruit(id:String,ftype:String)
case class Basket(b:Map[Fruit,Apple])
object Apple {
implicit val format = Json.format[Apple]
}
object Basket {
implicit val keyReads: KeyReads[Fruit] = s => ???
implicit val keyWrites: KeyWrites[Fruit] = f => s"${f.id}/${f.ftype}"
implicit val format = Json.format[Basket]
}
val b = Basket(Map(Fruit("1", "sw") -> Apple("2", "boskop")))
Json.stringify(Json.toJson(b)) // -> {"b":{"1/sw":{"id":"2","name":"boskop"}}}
https://scastie.scala-lang.org/XbFY6amKSb6BCVCrGmgrBQ
Upvotes: 1