Search code examples
scalaplay-json

Play JSON Implicit Resolution For Sealed Trait Types


I have a sealed trait that is implemented by two case classes. I then wrote implicit Reads and Writes for these types like this:

  implicit val myCaseClassWrites: Writes[MySealedTrait] = Writes {
    case CaseClass1(a, b, c) => Json.toJson(
      a,
      b,
      c
    )
    case CaseClass2(a, b, c, d) => Json.toJson(
      a,
      b,
      c,
      d
    )
  }

When I used this in my Controller where I'm writing the response to a client as JSON, it fails compilation with the following error:

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

However, when I wrote an explicit Writes like this below:

  implicit val caseClass2JSONWrites: Writes[CaseClass2] = Writes { caseClass2 =>
    Json.toJson(caseClass2.a,
      caseClass2.b,
      caseClass2.c,
      caseClass2.d
    )
  }

It worked. Why is this? Any ideas?


Solution

  • This is somehow expected. You need to either:

    1. cast your values to be of type MySealedTrait
    2. or, explicitly declare the Writes for each case class

    If you go for (1) this will look something like this:

    Json.toJson((caseClassValue: MySealedTrait))
    

    If you go for (2), you have to change your serializers like this:

    implicit val myCaseClass1Writes: Writes[CaseClass1] = ???
    
    implicit val myCaseClass2Writes: Writes[CaseClass2] = ???
    
    implicit val myCaseClassWrites: Writes[MySealedTrait] = Writes {
        case c1: CaseClass1 => myCaseClass1.writes(c1)
        case c2: CaseClass2 => myCaseClass2.writes(c2)
      }
    

    Maybe you don't actually need the serializer for the trait if you only ever serialize known case class subtypes.