Getting implicit val from the companion object - scala

I'm playing with Scala Spray. I enjoy working with it but can't figure out one thing.
This code compiles fine:
import spray.http.MediaTypes._
import spray.routing.HttpService
import spray.json.{DefaultJsonProtocol, _}
import spray.httpx.SprayJsonSupport._
trait StatusService extends HttpService {
case class StatusResponse(status: String)
object StatusResponseProtocol extends DefaultJsonProtocol {
implicit val statusResponse = jsonFormat1(StatusResponse)
}
import StatusResponseProtocol._
val statusRoute =
path("status") {
get {
respondWithMediaType(`application/json`) {
complete {
StatusResponse("OK")
}
}
}
}
}
But it doesn't compile (can't find json serializer) when I move case class & protocol to the companion object.
trait StatusService extends HttpService {
import StatusResponseProtocol._
val statusRoute =
path("status") {
get {
respondWithMediaType(`application/json`) {
complete {
StatusResponse("OK")
}
}
}
}
}
object StatusService {
case class StatusResponse(status: String)
object StatusResponseProtocol extends DefaultJsonProtocol {
implicit val statusResponse = jsonFormat1(StatusResponse)
}
}
I do not understand why..

I think the problem might be in your import statement. If you import from a companion object, it should be done like this:
trait StatusService extends HttpService {
import StatusService.StatusResponseProtocol._
The rest of the code doesn't have to be changed.

I think I've had pretty much the same problem. Try replacing:
import spray.httpx.SprayJsonSupport._
with
import spray.json._
It worked for me.

I noticed today (in another context, not Spray) that providing a type for the implicit val in a companion object made it visible.
So, I'm thinking whether this would make it work in your case:
implicit val statusResponse: RootJsonFormat[StatusResponse] = jsonFormat1(StatusResponse)
Note: I'm not sure of the type I added - it may not be what jsonFormat1 returns. Also, the Spray.json documentation does not use types. Anyways, if someone has the time to try this out, I'd be interested to know..

Related

Cannot understand Scala method definition

This is some code from Alvin Alexander's minimal Scala Websocket server.
package controllers
import play.api.mvc._
import play.api.libs.streams.ActorFlow
import javax.inject.Inject
import akka.actor.ActorSystem
import akka.stream.Materializer
import models.SimpleWebSocketActor
import play.api.libs.json._
class WebSocketsController #Inject() (cc: ControllerComponents)(implicit system: ActorSystem)
extends AbstractController(cc)
{
def index = Action { implicit request: Request[AnyContent] =>
logger.info("index page was called")
Ok(views.html.index())
}
}
What I'm curious about is the method definition for index. The notation is different to the normal method definition I've seen in Scala. Could someone explain what is going on here, and possibly point to some docs on this syntax? I haven't been able to find anything.
This definition is a combination of several syntax features of Scala but in the end there's nothing that special about it.
It's equivalent to something like this:
def index = {
def handleRequest(request: Request[AnyContent]) = {
implicit req = request
logger.info("index page was called")
Ok(views.html.index())
}
Action.apply(handleRequest) // Replaced by Action(...), then Action { ... }
}

Check what the method of mocked object receives

In my project, whenever a class produces some output, instead of doing println it calls OutputStore.write, which is a class and method I defined.
I am trying to test the output of another class so I mocked OutputStore. I want to see what parameters it receives to OutputStore.write.
val mockOutputStore = mock[OutputStore]
I would like to do something like this:
val argument = ArgumentCaptor.forClass(classOf[OutputStore])
verify(mockOutputStore).write(argument.capture())
assertEquals("some parameter", argument.getValue())
However, this doesn't compile as verify is not even recognized.
The signature of my test class is this:
class SomeUnitTestSet extends org.scalatest.FunSuite with MockitoSugar with PropertyChecks
Any idea how to check what parameters a mocked object's method receives?
Here is a translation of what #JBNizet suggested into a Scala code
Assuming you have your OutputStore class
class OutputStore {
def write(msg: String) = {
println(msg)
}
}
and some OutputStoreApiUser class
class OutputStoreApiUser(val outputStore: OutputStore) {
def foo(): Unit = {
outputStore.write("some parameter")
outputStore.write("some parameter2")
}
}
Then your test might be something like this (in real life you probably #Inject outputStore but this is not relevant here):
import org.mockito.Mockito.verify // static import!
import org.scalatest.mockito.MockitoSugar
import org.scalatest.prop.PropertyChecks
class SomeUnitTestSet extends org.scalatest.FunSuite with MockitoSugar with PropertyChecks {
test("Capture calls"){
val mockOutputStore = mock[OutputStore]
val apiUser = new OutputStoreApiUser(mockOutputStore)
apiUser.foo()
verify(mockOutputStore).write("some parameter")
verify(mockOutputStore).write("some parameter2")
}
}
This one compiles and works for me as I would expect

Serialize class as its one member with Jackson

Sometimes the class has only one member to serialize (other members are transient), and I would like to serialize and deserialize this class as its only member.
Consider following code:
import com.fasterxml.jackson.databind.ObjectMapper
import com.fasterxml.jackson.module.scala.DefaultScalaModule
import com.fasterxml.jackson.module.scala.experimental.ScalaObjectMapper
case class Content(i:Seq[Int])
case class Wrap(content:Content)
object Main extends App {
val om = new ObjectMapper() with ScalaObjectMapper {
registerModule(new DefaultScalaModule)
}
val roots = Wrap(Content(Seq(1,2,3)))
val out = om.writeValueAsString(roots)
println(out)
val test = om.readValue(out, classOf[Wrap])
println(test)
}
The result of serialization of Wrapis {"content":{"i":[1,2,3]}}.
I would like to get {"i":[1,2,3]} only. I guess I could do this with custom serializer/deserializer, but given in real case the content is a complex class, this would mean I would have to serialize the content manually, if I am not mistaken. I would prefer some more straightforward solution.
Is it possible to "delegate" the serialization/deserialization to a member/constructor parameter?
It can be done using converters, which can be used to modify Jackson behaviour using JsonSerialize and JsonDeserialize properties.
import com.fasterxml.jackson.databind.annotation.{JsonSerialize, JsonDeserialize}
import com.fasterxml.jackson.databind.util.StdConverter
#JsonDeserialize(converter=classOf[WrapConverterDeserialize])
#JsonSerialize(converter=classOf[WrapConverterSerialize])
case class Wrap(content:Content)
class WrapConverterDeserialize extends StdConverter[Content,Wrap] {
override def convert(value: Content) = new Wrap(value)
}
class WrapConverterSerialize extends StdConverter[Wrap,Content] {
override def convert(value: Wrap) = value.content
}

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

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
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)
}
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.
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.

Spray.io case class extraction error

I'm learning spray.io, and I'm stuck in a problem.. I'm trying to test the case class extraction of several GET parameters. My code is inspired by the examples from the documentation page :
package com.example
import akka.actor.Actor
import spray.routing._
import spray.http._
import MediaTypes._
class ServiceActor extends Actor
with ServiceHello {
def actorRefFactory = context
def receive = runRoute(testRoute)
trait ServiceHello extends HttpService with Controls {
case class Color(keyword: String, sort_order: Int, sort_key: String)
val route =
path("test") {
parameters('keyword.as[String], 'sort_order.as[Int], 'sort_key.as[String]).as(Color) { color =>
handleTestRoute(color) // route working with the Color instance
}
}
}
This code should be ok, but when I try to run it, I got the following errors :
Cannot resolve symbol as (on top of "as(Color)" )
Missing parameter type: color (on top of "{ color =>")
I understand these errors, but i do not understand why they come...
I'm running Scala 2.10.3
Am I doing something wrong ?
Thats working for me (scala 2.10.4, spray 1.3.1):
import akka.actor.Actor
import spray.routing._
import spray.http._
import MediaTypes._
class ServiceActor extends Actor with ServiceHello {
def actorRefFactory = context
def receive = runRoute(testRoute)
}
trait ServiceHello extends HttpService {
case class Color(keyword: String, sort_order: Int, sort_key: String)
val testRoute =
path("test") {
parameters('keyword.as[String], 'sort_order.as[Int], 'sort_key.as[String]).as(Color) { color =>
//handleTestRoute(color) // route working with the Color instance
complete {
<h1>test route</h1>
}
}
}
}
Don't know what Controls is, so I just commented it.