Spray List Marshaller not found - scala

This code results in a compile error of could not find implicit value for parameter marshaller:
spray.httpx.marshalling.ToResponseMarshaller[List[akka.actor.ActorRef]].
I don't think the problem is the ActorRef, as changing this to .mapTo[List[String]] shows the same compile error
In general, it's somewhat confusing how spray does marshalling with all the implicits - is there a way to make this explicit e.g. ListProtocol.marshal(value)?
import akka.actor.Actor
import spray.http.HttpResponse
import spray.http.HttpRequest
import spray.http.Uri
import spray.http._
import spray.routing._
import HttpMethods._
import akka.actor.ActorRef
import akka.pattern.ask
import scala.concurrent.duration._
import scala.concurrent.ExecutionContext.Implicits.global
import scala.util.Success
import scala.util.Failure
import spray.http.StatusCodes.InternalServerError
import spray.json.DefaultJsonProtocol
import spray.httpx.SprayJsonSupport._
import spray.httpx.marshalling._
import spray.http._
class HttpApi(val manager: ActorRef) extends HttpServiceActor {
def receive = runRoute {
path("nodes") {
get {
onComplete(manager.ask(NodeList())(3.seconds).mapTo[List[ActorRef]]) {
case Success(value) => {
// Compile error happens here
complete(value)
}
case Failure(ex) => {
complete(InternalServerError, s"An error occurred: ${ex.getMessage}")
}
}
}
}
}
}

Change this import
import spray.json.DefaultJsonProtocol
to
import spray.json.DefaultJsonProtocol._
That is, you want to import the implicits defined in that object, not the object itself.
Alternatively you can extend the trait to pick up the implicits:
class HttpApi(val manager: ActorRef) extends HttpServiceActor
with DefaultJsonProtocol {

Related

type mismatch; found : play.api.libs.iteratee.Enumerator[reactivemongo.bson.BSONDocument] required: Boolean

package repos
import javax.inject.Inject
import play.api.libs.json.{JsObject, Json}
import play.modules.reactivemongo.{ReactiveMongoApi, ReactiveMongoComponents,ReactiveMongoPlugin}
import play.modules.reactivemongo.json._
import play.modules.reactivemongo.json.collection.JSONCollection
import reactivemongo.api.{QueryOpts, ReadPreference}
import reactivemongo.api.commands.WriteResult
import reactivemongo.bson.{BSONDocument, BSONObjectID}
import reactivemongo.bson._
import reactivemongo.api.collections.bson.BSONCollection
import scala.language.existentials
import scala.concurrent.{ExecutionContext, Future}
import scala.util.{Try, Success, Failure}
import models._
import play.api.Logger
import play.api.libs.iteratee.Enumerator
trait MongoDao[T] extends DaoHelper{
val collectionName: String
import play.api.Play.current
lazy val reactiveMongoApi = current.injector.instanceOf[ReactiveMongoApi]
def collection = reactiveMongoApi.db.collection[BSONCollection](collectionName)
/**
* Inserts a list of T into mongo
*
* #param docList - List of T
* #param writer - The BSONDocumentWriter on the companion object for T
* #return - a Future[Try[Int]]
*/
def insert(docList: List[T])(implicit writer: BSONDocumentWriter[T]): Future[Try[Int]] = {
Logger.debug(s"Inserting document: [collection=$collectionName, data=$docList]")
val enumerator = Enumerator.enumerate(docList.map( t => writer.write(t)))
collection.bulkInsert(enumerator).map{ Success(_)}
}
}
Anyone know what is the problem come from?

Play Controllers functional test with PlaySpec

I'm using Play Scala 2.5, I would like to write functional tests for a controller class.
This is the signature of my controller class with a action I would like to test for example.
class MyController #Inject()(implicit context: ExecutionContext, val messagesApi: MessagesApi, val dao: Dao) extends Controller with I18nSupport {
def getMyData = Action.async { implicit request =>
dao.getMyData map { myData =>
Ok(views.html.render(myData))
}.recover {
// recover.
}
}
}
Here is my Dao class that is used in my controller's action :
import play.api.Configuration
class Dao #Inject()(val ws: WSClient, val configuration: Configuration) {
val myConfigData: List[MyConfigData] = { ... } // Get data from configuration
def getMyData(): Future[List[MyData]] = {
// use myConfigData and call web service (ws) to get some data
}
}
I would like to test my controller's action using different configuration in my Dao class.
I manage to do it and my test class is working but I would like some advices to improve the code.
package controllers
import play.core.server.Server
import org.scalatest._
import Inspectors._
import org.scalatestplus.play._
import play.api.routing.sird._
import play.api.libs.json._
import play.api.mvc._
import play.api.Play
import play.api.test._
import play.api.i18n.MessagesApi
import play.api.Configuration
import play.api.test.Helpers.{ OK, status, contentAsString }
import org.scalatest.concurrent.ScalaFutures
import scala.concurrent.Future
import scala.concurrent.Await
import scala.concurrent.duration._
import play.api.libs.json._
import play.api.mvc._
import scala.concurrent.ExecutionContext
import com.typesafe.config.ConfigFactory
import dao.{ Dao }
import akka.util.Timeout
class MyControllerFunctionalSpec extends PlaySpec with OneAppPerSuite with ScalaFutures {
implicit val messagesApi = app.injector.instanceOf[MessagesApi]
implicit val ec = app.injector.instanceOf[ExecutionContext]
implicit val timeout = Timeout(5 seconds)
trait OneConfig {
val config = ConfigFactory.parseString(""" my config """)
}
trait AnotherConfig {
val config = ConfigFactory.parseString(""" my other config """)
}
"MyController" should {
"get some data" in new OneConfig {
Server.withRouter() {
case GET(p"/url1/some/data") => Action {
Results.Ok(Json.arr(Json.obj("name" -> "data1")))
}
} { implicit port =>
WsTestClient.withClient { client =>
implicit val dao = new Dao(client, Configuration(config))
val myController = new MyController()
val result = myController.getMyData(FakeRequest())
status(result) must equal(OK)
//println(contentAsString(result))
}
}
}
}
}
It is working like this but I was guided by compilation error and by fixing them to get it to work.
I would like help or advices to do it the right way.
Any advice welcome.

How to use Spray JSON serializer in abstract way?

Any idea why this code doesn't work? I'm trying to have serialize method to all my exceptions to avoid the need for pattern matching for every exception. With the code below, I just need to case ex:MarshallableException => ex.serialize
The below code can run stand-alone. It will print Start... Serialization Failure shared.utils.InvalidID :(
import scala.util.{Failure, Success}
import akka.http.scaladsl.marshalling.{Marshaller, Marshal}
import akka.http.scaladsl.marshallers.sprayjson.SprayJsonSupport._
import akka.http.scaladsl.model.ResponseEntity
import spray.json.DefaultJsonProtocol
import scala.concurrent.Future
import scala.concurrent.ExecutionContext.Implicits.global
trait MarshallableException{
def serialize: Future[ResponseEntity]
}
case class InvalidID(error:String, code: String= "6001") extends Exception with MarshallableException {
import Exceptions._
override def serialize: Future[ResponseEntity] = {
Marshal(this).to[ResponseEntity]
}
}
object Exceptions extends DefaultJsonProtocol{
implicit val invalidIDFormat = jsonFormat2(InvalidID.apply)
}
object Test extends App{
val ex = new InvalidID("Test exception")
println("Start...\n")
ex.serialize.onComplete{
case Success(e) => println(e.toString())
case Failure(f) =>
println("Serialization Failure " + f.toString)
}
}

How to complete a request in another actor when using akka-http

I am using akka-http 1.0 and I would like to use a route defined as
def route: Route = path("") {
// start actor with requestContext
// call requestContext.complete(...) in actor with the result
}
How do I accomplish this?
Elaborating on #jrudolph's comment, the below code satisfies your requirements of dispatching RequestContext values to an Actor. Your question indicated that you wanted a new Actor for each request; however, the below code uses the same Actor for all requests which I think is a more efficient/likely use case. The Actor creation can always be moved inside handleRequest if needed.
First we need an Actor for processing a request to a response:
import akka.actor.Actor
import akka.http.scaladsl.server.{RequestContext, RouteResult}
import akka.http.scaladsl.model.HttpResponse
class RequestActor extends Actor {
//business logic - returns empty HttpResponse
def handleRequestMessage(requestContext : RequestContext) =
RouteResult.Complete(new HttpResponse())
override def receive = {
case reqContext : RequestContext =>
sender ! handleRequestMessage(reqContext)
}
}//end class RequestActor
Now create a utility function for querying the Actor:
import akka.actor.ActorRef
import scala.concurrent.Future
import akka.pattern.ask
object RequestActor {
val handleRequest : ActorRef => RequestContext => Future[RouteResult] =
(actorRef) =>
(requestContext) =>
ask(actorRef,reqContext).mapTo[RouteResult]
}
And all that is left to do is wire everything together into a service:
import akka.actor.{ActorSystem, Props}
import akka.stream.ActorMaterializer
import akka.http.scaladsl.Http
import akka.http.scaladsl.server.Directives.{get,path}
import akka.util.Timeout
object RouteActorTest extends App {
implicit val as = ActorSystem("RouteActorTest")
implicit val timeout = new Timeout(1000)
val sendRequestToActor : RequestContext => Future[RouteResult] =
RequestActor handleRequest (as actorOf Props[RequestActor])
val route = path("")(get(sendRequestToActor))
//rest of application...
}//end object RouteActorTest
you may try even better like:
package controllers
import akka.actor.{Actor, ActorSystem, Props}
import akka.stream.ActorMaterializer
import scala.concurrent.{Await, Future}
import akka.http.scaladsl.server.Directives._
import akka.stream.ActorMaterializer
import akka.util.Timeout
import akka.pattern.ask
import scala.concurrent.Await
import scala.concurrent.duration._
import scala.io.StdIn
import akka.actor._
import akka.util.Timeout
case object Message
class TestActor(name:String) extends Actor {
def receive = {
case Message =>
sender ! "Testing Ask pattern Approach"
println(s"hello from $name")
case _ =>
println("that was unexpected")
}
}
object AskTest extends App {
implicit val system= ActorSystem("myactor")
implicit val material=ActorMaterializer()
// implicit val props=Props.empty
implicit val timeout = Timeout(5 seconds)
implicit val result =system.actorOf(Props(new TestActor("TestingName")),name = "Scala")
val future3:Future[String]= ask(result ,Message).mapTo[String]
val results = Await.result(future3, 2 seconds)
println(results)
}

How to apply toJson to instance of a case class using spray-json library

Registration.scala
package model
import akka.actor.Actor
import spray.json._
import DefaultJsonProtocol._
case class Registration(
system: String,
identity: String)
object RegistrationProtocol extends DefaultJsonProtocol {
implicit val adsRegistrationFormat = jsonFormat2(Registration)
}
RegistrationService.scala
import akka.actor.{Props, ActorLogging, Actor}
import model.Registration
object RegistrationsService {
case class PostRegistrationMessage(registration: Registration)
def props(property: String) = Props(classOf[RegistrationsService], property)
}
class RegistrationsService(property: String) extends Actor with ActorLogging {
import RegistrationsService._
def receive = {
case PostRegistrationMessage(registration) => {
import model.RegistrationProtocol._
val json = registration.toJson
}
}
}
Can anyone help me understand why this is failing with compilation error "value toJson is not a member of model.Registration" and how to fix it. It if failing in the last line of the code above, which is "val json = registration.toJson"
You need to import implicit operations provided by spray in RegistrationService.scala too
import model.RegistrationProtocol._
import spray.json._