Search code examples
scalaoopimplicitsprayspray-json

Implicit value polymorphism in Scala and Spray


I'm trying to create a common trait for my Actors to avoid code copypasting, basically like this:

import akka.actor.Actor
import spray.json._

import scala.concurrent.Future

trait ActorResponsive[T] extends Actor {
  import DefaultJsonProtocol._
  import context.dispatcher

  case class Response(success: Boolean,
                      single: Option[T] = None,
                      multiple: Option[Seq[T]] = None,
                      message: Option[String] = None)

  implicit val responseFormat = jsonFormat4(Response)

  def makeResponse(f: Future[Any]) =
    f.map { /*...*/ }.recover { /*...*/ }
        .map { case r => r.toJson.compactPrint }
}

Regardless other code flaws, I'm trying to make responseFormat resolved polymorphically, e.g.:

class PostgresItemActor extends ActorResponsive[Item] {
  import com.blahblah.models.ItemJsonProtocol._
  override def receive = makeResponse(someFuture)
}
...
class PostgresEventActor extends ActorResponsive[Event] {
  import com.blahblah.models.EventJsonProtocol._
  override def receive = makeResponse(someFuture)
}

So JsonProtocol for each time responseFormat is called will be resolved regarding the import in the class, implementing the ActorResponsive trait. As for now, I'm getting a compile error:

Cannot find JsonWriter or JsonFormat type class for ActorResponsive.this.Response

Probably I'm getting some concept of OOP wrong here, but is it possible to resolve jsonFormat(Response) for T or achieve some behaviour like this?


Solution

  • It looks like you need to provide the JsonWriter as a parameter to your makeResponse function.

    Something along the lines of:

    def makeResponse[T: JsonWriter](f: Future[T]) =
      f.map { /*...*/ }.recover { /*...*/ }
        .map { case r => r.toJson.compactPrint }