I have a trait that has many implementations. When in json format you can distinguish easly between them by kind
property. Is there a some simple way to have json4s pick correct implementation based on that property?
I would prefer to avoid writing huge custom serializer to handle each case individually.
I was hoping something like this would work:
class ExampleTest extends WordSpecLike with Matchers {
implicit val formats: Formats = DefaultFormats + new CarSerializer
val teslaJson =
"""
|{
| "name": "Tesla",
| "kind": "electric",
| "batteryCapacity": 250.0
|}
""".stripMargin
val bmwJson =
"""
|{
| "name": "BMW",
| "kind": "petrol",
| "tankCapacity": 70.0
|}
""".stripMargin
val tesla = ElectricCar(
"Tesla", "electric", 250.0
)
val bmw = PetrolCar(
"BMW", "petrol", 70.0
)
"JSON4s" should {
"extract electric car" in {
parse(teslaJson).extract[ElectricCar] should be(tesla)
}
"extract petrol car" in {
parse(bmwJson).extract[PetrolCar] should be(bmw)
}
"extract electric car with CarSerializer" in {
parse(teslaJson).extract[Car] should be(teslaJson)
}
}
}
class CarSerializer extends CustomSerializer[Car](_ => ( {
case car: JObject =>
car \ "kind" match {
case JString(v) if v == "electric" => car.extract[ElectricCar]
case JString(v) if v == "petrol" => car.extract[PetrolCar]
}
}, {
case car: Car => Extraction.decompose(car)
}))
sealed trait Car {
def name: String
def kind: String
}
case class ElectricCar(
name: String,
kind: String,
batteryCapacity: Double
) extends Car
case class PetrolCar(
name: String,
kind: String,
tankCapacity: Double
) extends Car
Unfortunately it does not work as extract
and decompose
functions require implicit formats to be present but the serializer itself is meant to be part of the formats.