Reputation: 24077
I have a json array of settings like so:
[
{
"name": "Company Name",
"key": "company_name",
"default": "Foo"
}, {
"name": "Deposit Weeks",
"key": "deposit_weeks",
"default": 6
}, {
"name": "Is VAT registered",
"key": "vat_registered",
"default": false
}
]
I want to parse this into a Seq
of Setting
objects. I have tried to define my json format by using a trait and defining the different case classes according to the data type in the json object:
sealed trait Setting
case class StringSetting(name: String, key: String, default: String) extends Setting
case class IntSetting(name: String, key: String, default: Int) extends Setting
case class BoolSetting(name: String, key: String, default: Boolean) extends Setting
Now I try to parse the json:
val json = Json.parse(jsonStr)
implicit val jsonFormat: Format[Setting] = Json.format[Setting]
val result = Try(json.as[Seq[Setting]])
Here I get a compile error:
Error:(19, 61) No unapply or unapplySeq function found implicit val jsonFormat: Format[Setting] = Json.format[Setting]
Is there a way to map each setting to its appropriate case class?
Upvotes: 4
Views: 1930
Reputation: 41
The naive approach would be to provide Reads[Setting](if your aim just to convert json to object) so that JSON deserializer able to build the right variant of Setting.
import play.api.libs.json._
import play.api.libs.functional.syntax._
implicit val settingReads: Reads[Setting] = (__ \ "default").read[String].map[Setting](StringSetting) |
(__ \ "default").read[Int].map[Setting](IntSetting) |
(__ \ "default").read[Boolean].map[Setting](BoolSetting)
However, this would not work if you have same type for 'default' in different sub classes. In this case JSON deserializer unable to distinguish between those two case classes.
Another approach is to use play json variant library.
import julienrf.variants.Variants
sealed trait Setting
case class StringSetting(name: String, key: String, default: String) extends Setting
case class IntSetting(name: String, key: String, default: Int) extends Setting
case class BoolSetting(name: String, key: String, default: Boolean) extends Setting
object Setting {
implicit val format: Format[Setting] = Variants.format[Setting]
}
Variant.format provides both read and writes for Setting. Make sure that assignment of 'implicit val format' should happen after all possible subclass has been declared.
For more information regarding play json variant library click here
Upvotes: 4