Spray won't convert my case class to json and expect a spray.httpx.marshalling.ToResponseMarshallable

ydemartino picture ydemartino · Jul 11, 2014 · Viewed 7.4k times · Source

I'm trying to reprocude this or this, but I keep getting an error I am not able to fix...

First of all, here are my dependencies:

compile 'io.spray:spray-can_2.11:1.3.1'
compile 'io.spray:spray-routing_2.11:1.3.1',
compile 'io.spray:spray-json_2.11:1.2.6'

Now what I'm trying to do is:

class WHttpService extends Actor with HttpService with ActorLogging {

  implicit def actorRefFactory = context

  def receive = runRoute(route)

  lazy val route = logRequest(showReq _) {
    // Way too much imports but I tried all I could find
    import spray.json._
    import DefaultJsonProtocol._
    import MasterJsonProtocol._
    import spray.httpx.SprayJsonSupport._
    path("server" / Segment / DoubleNumber / DoubleNumber) { (login, first, second) =>
      get {
          complete {
            Answer(1, "test")
          }
      }
    }
  }

  private def showReq(req : HttpRequest) = LogEntry(req.uri, InfoLevel)
}

With:

case object MasterJsonProtocol extends DefaultJsonProtocol with SprayJsonSupport {
  import spray.json._

  case class Answer(code: Int, content: String)
  implicit val anwserFormat: JsonFormat[Answer] = jsonFormat2(Answer)
}

Now I get this error:

Error:(42, 19) type mismatch;
 found   : MasterJsonProtocol.Answer
 required: spray.httpx.marshalling.ToResponseMarshallable
            Answer(1, "test")
                  ^

I tried a lot of things but can't manage to make it works. I tried with

Answer(1, "test").toJson
Answer(1, "test").toJson.asJsObject

Finally what I did was

complete {
    Answer(1, "test").toJson.compactPrint
}

This works but it is sent to the client as Content-Type: text/plain when I need application/json.

Anyone see what the problem is here?

Edit: I added a sample project on github https://github.com/ydemartino/spray-test

Answer

Gangstead picture Gangstead · Jul 11, 2014

Move your model outside of the json protocol and make it a regular object (not a case object)

case class Answer(code: Int, content: String)

object MasterJsonProtocol extends DefaultJsonProtocol {
  implicit val anwserFormat = jsonFormat2(Answer)
}

Edit

Also clean up your imports:

class WHttpService extends Actor with HttpService with ActorLogging {

  implicit def actorRefFactory = context

  def receive = runRoute(route)

  lazy val route = logRequest(showReq _) {
    // Way too much imports but I tried all I could find
    import MasterJsonProtocol._
    import spray.httpx.SprayJsonSupport._

    path("server" / Segment / DoubleNumber / DoubleNumber) { (login, first, second) =>
      get {
          complete {
            Answer(1, "test")
          }
      }
    }
  }

  private def showReq(req : HttpRequest) = LogEntry(req.uri, InfoLevel)
}