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

3

7

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

Hippomenes answered 11/7, 2014 at 19:3 Comment(4)
+1. This is an awesome first post, welcome on SO :DElbe
I should have asked this in a top level comment. What version of Scala are you using? It looks like Spray doesn't have a release yet for 2.11 github.com/spray/spray/issues/790Glasscock
I saw this issue, but according to the official documentation: spray.io/project-info/current-versions "spray 1.3.1 is built against Scala 2.10.3 and Akka 2.3.0 as well as Scala 2.11.1 and Akka 2.3.2." As I could get the files using 'io.spray:spray-can_2.11:1.3.1' I thought they fixed it in the meantime. I will try with scala 2.10 to see if my code compile.Hippomenes
I added a sample project on github that allows to reproduce the problem. This project uses scala 2.10: github.com/ydemartino/spray-testHippomenes
G
2

I created a pull request to fix your problem: https://github.com/ydemartino/spray-test/pull/1

The json protocol object has to be declared before it can be used implicitly. I'm not wholly sure why the compiler can't figure it out, but moving the object declaration to the top fixed it.

For your actual project make sure to declare packages in each file then use those packages to in the import statements.

Glasscock answered 11/7, 2014 at 21:13 Comment(1)
Wow thanks! I cannot figure out why we have to declare it before either... Anyway there was a problem with the scala version, I tried the same code changing the dependencies to 2.11 and it won't compile with the error I had before...Hippomenes
G
4

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)
}
Glasscock answered 11/7, 2014 at 19:25 Comment(4)
Hey, thanks for the answer, I did what you said, turn it into an object (I actually did not notice it was a case object), removed the with SprayJsonSupport and moved the model outside but I am getting exactly the same error.Hippomenes
Hey, I tried with the imports cleaned up. Same thing. My IDE has the two of them greyed out as "Unused import statement", am I missing a dependency for this to work?Hippomenes
What version of Scala are you using?Glasscock
Scala version 2.11.1 with jdk 1.8.05. I switch to jdk 1.7.60 to check if java was messing my build, but I got the same result.Hippomenes
G
2

I created a pull request to fix your problem: https://github.com/ydemartino/spray-test/pull/1

The json protocol object has to be declared before it can be used implicitly. I'm not wholly sure why the compiler can't figure it out, but moving the object declaration to the top fixed it.

For your actual project make sure to declare packages in each file then use those packages to in the import statements.

Glasscock answered 11/7, 2014 at 21:13 Comment(1)
Wow thanks! I cannot figure out why we have to declare it before either... Anyway there was a problem with the scala version, I tried the same code changing the dependencies to 2.11 and it won't compile with the error I had before...Hippomenes
C
0

In my case the name of the unresolvable implicit format instance conflicted with a local definition, so it got shadowed. The compiler was graciously silent about that. Only discovered that by accident after hours of head-banging.

Cowardice answered 21/10, 2016 at 12:26 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.