Denis Mikhaylov
Denis Mikhaylov

Reputation: 2045

Serialize to JSON a list of case classes having common trait

Let's say I have

trait T
case class A(s: String) extends T
case class B(s: String, i: Int) extends T

I need to be able to serialize a List[T]

After declaring

implicit val aWrites = Json.writes[A]
implicit val bWrites = Json.writes[B]

I try to

val list = List(A("1"), B("2", 2))
Json.toJson(list)

but compiler says that

No Json serializer found for type T. Try to implement an implicit Writes or Format for this type.

my solutions is

implicit val tWrites = new Writes[T] {
    def writes(t: T) = t match {
        case a: A => Json.toJson(a)
        case b: B => Json.toJson(b)
    }
}

I don't like it, because it requires to change tWrite for each new class extending T.

Is there a more flexible implementation?

Upvotes: 2

Views: 245

Answers (1)

Marius Soutier
Marius Soutier

Reputation: 11274

The Json.writes macro requires an unapply method, so you cannot use it with a trait. But even if you could, it would only serialize the parameters it knows from T. So your solution is the best you can do, although you probably (depending on use case) have to add a parameter that distinguishes between A and B when deserializing.

By the way, having to extend matches when you add a new type is a common problem (see expression problem). You should make your trait sealed so the compiler will inform you when a pattern match statement misses a newly added type.

Upvotes: 0

Related Questions