No apply function found when trying to convert a case class (derived from Trait) to Json

Viewed 86

I am struggling with a request to JSON conversion.

Error : No apply function found for CommonRequest

ClassA.scala

trait CommonRequest{
   //def someFunc()
   //val a: String
 }
    
object CommonRequest {
    implicit val CommonRequestRequestFormat: OFormat[CommonRequest] = Json.format[CommonRequest] // Error: No apply function found for CommonRequest
 }

ClassB.scala

case class DerivedRequestA(One: Int) extends CommonRequest{
  //Overridden def and vals
}

case class DerivedRequestB(Two: Int) extends CommonRequest{
  //Overridden def and vals
}

object DerivedRequestA {
  implicit val RequestAFormat: OFormat[DerivedRequestA] = Json.format[DerivedRequestA]
}

object DerivedRequestB {
  implicit val RequestAFormat: OFormat[DerivedRequestB] = Json.format[DerivedRequestB]
}

ClassC.scala

def CallAPI(request: CommonRequest): Future[CommonResponse] = {
    //call api with JSON request body
    request_body = toJsonStringValue(request) // This call needs write implicit
}

def toJsonStringValue[T](o: T)(implicit t: Writes[T]): String = {
  Json.toJson(o).toString()
}

Looks like, only companion object is not enough. What else I need to do here ?

1 Answers

The toJson method generates JSON based on the compile-time type of the object that is passed to it. In this case that type is CommonRequest which is a trait with no members or constructor, so the library has no way to read or write this.

To work properly the compiler needs to see the specific type of the object to be converted. This (totally untested) code may be what you want:

def CallAPI[T <: CommonRequest](request: T): Future[T] = {
   request_body = toJsonStringValue(request)
   // ...
}

This will call toJsonStringValue with the exact type of the request value, rather than the superclass type CommonRequest.

Related