having problems calling a method from controller in scala - scala

i'm using playframework with scala and slick.
in my dto (dao) I do this:
class processDTO #Inject() (protected val dbConfigProvider: DatabaseConfigProvider) extends HasDatabaseConfigProvider[JdbcProfile]
with ProcessTemplatesComponent {
import driver.api._
private val processTemplates = TableQuery[ProcessTemplates]
def getAll(): Future[Seq[ProcessTemplatesModel]] = db.run { processTemplates.to[Seq].result }
}
and in controller I do this:
#Singleton
class ProcessesController #Inject() (processDTO: processDTO, actionBuilder: ActionBuilders) extends Controller{
def getProcesses() = actionBuilder.DynamicAction(name = "pureLuck").defaultHandler() {
request =>
processDTO.getAll().map(_.map(result => {
}))
.map(result => Ok(Json.toJson(result)))
}
}
and now I got this error

First of all you need to import execution context. PlayFramework has his own context. Add this import play.api.libs.concurrent.Execution.Implicits._ Play documentation
Also you need to return something from this code of block:
_.map(result => {})
Currently you return Unit which can't be transformed to json.

The error tells you what you need to know. Adding import scala.concurrent.ExecutionContext.Implicits.global at the top of your file should fix it.

One issue is the lack of execution context as other had mentioned.
As of your json error, you need to implement a Write converter to transform your ProcessTemplatesModel objects into json.

Related

Returning a JSON array in Akka Http

I have an Akka HTTP server with routing defined like this:
case class FooResults(results: Seq[Tuple2[String, Tuple2[Double, Double]]])
object MainApp extends App with JsonSupport {
...
lazy val routes: Route =
pathPrefix("foo") {
pathEnd {
get {
entity(as[String]) { str =>
val results =
(fooActor ? Foo(str)).mapTo[FooResults]
complete(results)
}
}
}
}
...
And in the class I have injected the implicit json support:
trait JsonSupport extends SprayJsonSupport {
import DefaultJsonProtocol._
implicit val userFormat = jsonFormat1(FooResults)
}
Somehow sbt still reports with
Type mismatch - FooResults with ToResponseMashallable
Anyone had similar problems? Thanks!
I figured out myself. It was because there're two SprayJsonSupport classes in my project:
import spray.httpx.SprayJsonSupport
import akka.http.scaladsl.marshallers.sprayjson.SprayJsonSupport
Now obviously the latter is the correct one. Guess along the way since both Scala and Akka are evolving (fast), sometimes it becomes confusing with the namespaces and classes.

Scala Play run time injection based on request parameter

I am using Scala Play 2.6 and trying to use dependency injection to instantiate a service class based on request parameter. As below example code, the controller class get payment method from query string
package controllers
import com.google.inject.Inject
import play.api.mvc._
import scala.concurrent.ExecutionContext
class PaymentController #Inject()()
(implicit ec: ExecutionContext)
extends InjectedController {
def doPayment() = Action.async { implicit request =>
request.getQueryString("payment-method").getOrElse("") match {
case "paypal" => // Inject a PaypalPaymentService
val paymentService = Play.current.injector.instanceOf[PaypalPaymentService]
paymentService.processPayment()
case "creditcard" => // Inject a CreditCardPaymentService
val paymentService = Play.current.injector.instanceOf[CreditCardPaymentService]
paymentService.processPayment()
case _ => // Return error
}
}
}
And services class to process Paypal or CreditCard payment
package services
import scala.concurrent.Future
trait PaymentService {
def processPayment(): Future[Boolean]
}
package services
import com.google.inject.Inject
import scala.concurrent.{ExecutionContext, Future}
import play.api.libs.ws.WSClient
class PaypalPaymentService #Inject()(ws: WSClient)
(implicit ec: ExecutionContext)
extends PaymentService {
def processPayment(): Future[Boolean] = {
//Process paypal payment
}
}
class CreditCardPaymentService #Inject()(ws: WSClient)
(implicit ec: ExecutionContext)
extends PaymentService {
def processPayment(): Future[Boolean] = {
//Process credit card payment
}
}
For Play 2.5 onwards, Play.current and Play.application have been deprecated.
I have two questions:
Is the above example code a correct way to inject a class based on
request parameter? or is there some other better way to do so?
For Play 2.5/2.6, what is the way to get the application injector?
You have stated correctly that Play.current and Play.application have been deprecated and from 2.5 onwards the way to use them is indeed by injecting them.
I would change your controller definition so that you make use of DI to include the needed components. Something like:
class PaymentController #Inject()(configuration: Configuration)
(implicit ec: ExecutionContext) extends Controller {
// your code goes here
}
Now comes the tricky part. You might thing that it is possible just to inject application: play.Application but this is not entirely true because you are going to run into circular dependencies. This is normal because you want to inject the whole application while actually being in it. There is one hack for this and it is by injecting Provider[Application]. I call this a hack because normally you don't need/want to inject the whole application. In 99% of the cases you are interested only in specific parts - e.g. the Configuration, Environment, etc.
And here comes the solution. You can just inject your Injector
class PaymentController #Inject()(injector: Injector)
(implicit ec: ExecutionContext) extends Controller {
// your code goes here
}
From here the game is an easy one. Just use the Injector to get the needed services. Like this:
case "paypal" => // Inject a PaypalPaymentService
val paymentService = injector.instanceOf(classOf[PaypalPaymentService])
paymentService.processPayment()
Last words regarding the "correct way" of using this. I actually find your approach OK and would not necessarily change it. Just one idea in this direction is that you create a Module like this:
import com.google.inject.AbstractModule
import com.google.inject.name.Names
class PaymentModule extends AbstractModule {
def configure() = {
bind(classOf[PaymentService])
.annotatedWith(Names.named("paypal"))
.to(classOf[PaypalPaymentService])
bind(classOf[PaymentService])
.annotatedWith(Names.named("creditcard"))
.to(classOf[CreditCardPaymentService])
}
}
Having a common trait (as you do it) helps in this case and you can have multiple implementations, even mocked ones for your tests. The module will be registered automatically if it lies in the root package. Otherwise you should tell Play the location of it:
play.modules.enabled += "modules.PaymentModule"

How to mock using external call in Akka Actor using ScalaTest

I am new to entire ecosystem including Scala, Akka and ScalaTest
I am working on a problem where my Actor gives call to external system.
case object LogProcessRequest
class LProcessor extends Actor {
val log = Logging(context.system, this)
def receive = {
case LogProcessRequest =>
log.debug("starting log processing")
LogReaderDisruptor main(Array())
}
}
The LogReaderDisruptor main(Array()) is a Java class that does many other things.
The test I have currently looks like
class LProcessorSpec extends UnitTestSpec("testSystem") {
"A mocked log processor" should {
"be called" in {
val logProcessorActor = system.actorOf(Props[LProcessor])
logProcessorActor ! LogProcessRequest
}
}
}
where UnitTestSpec looks like (and inspired from here)
import akka.actor.ActorSystem
import akka.testkit.{ImplicitSender, TestKit}
import org.scalatest.matchers.MustMatchers
import org.scalatest.{BeforeAndAfterAll, WordSpecLike}
abstract class UnitTestSpec(name: String)
extends TestKit(ActorSystem(name))
with WordSpecLike
with MustMatchers
with BeforeAndAfterAll
with ImplicitSender {
override def afterAll() {
system.shutdown()
}
}
Question
How can I mock the call to LogReaderDisruptor main(Array()) and verify that it was called?
I am coming from Java, JUnit, Mockito land and something that I would have done here would be
doNothing().when(logReaderDisruptor).main(Matchers.<String>anyVararg())
verify(logReaderDisruptor, times(1)).main(Matchers.<String>anyVararg())
I am not sure how to translate that with ScalaTest here.
Also, This code may not be idiomatic, since I am very new and learning
There are a few ways to do this. The kind of OO way is to wrap logDisrupter as an object and pass it in. I would set up a companion object to instantiate the actor. Something like below. Then you can pass alternate implementation. You can also achieve a similar approach by using traits and mixing in an alternative logDisrupter only as needed.
object LProcessor {
def props(logDisrupter : LogDisrupter) = Props(new LProcessor(logDisrupter))
}
class LProcessor(logDisrupter : LogDisrupter) extends Actor {
val log = Logging(context.system, this)
def receive = {
case LogProcessRequest =>
log.debug("starting log processing")
logDisrupter.doSomething();
}
}
Then instatiate as
val logProcessorActor = system.actorOf(LProcessor.props(logDisrupter))

Getting implicit val from the companion object

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

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
}