How to setup my UserService using the cake pattern inside of play? - scala

Currently I am using guice to wireup my UserService inside of a controller like:
#Singleton
class UserController #Inject()(userService: UserService) extends Controller {
def show(userId: Int) {
val user = userService.get(userId)
Ok("hello " + user.name)
}
}
My UserService looks like:
abstract class UserService {
def get(userId: Int): User
}
class UserServiceImpl #Inject()(val userDao: UserDao) extends UserService {
def get(userId: Int): User = {
// ....
}
}
If I wanted to drop guice as a dependency and use the cake pattern, what would the code look like and how would I integrate this into Play so I could use this service in my Controllers?

Here's a suggestion with package names to give you an idea of how to organize all of this.
package controllers.users
trait UserController extends Controller {
this: UserService =>
def show(userId: Int) = {
val user = this.get(userId)
Ok("hello " + user.name)
}
}
package services.users
trait UserService {
def get(userId: Int): User
}
package services.users.impl
trait UserServiceImpl extends UserService {
def get(userId: Int) = { /*implementation*/ }
}
package controllers
object UserController extends UserController with UserServiceImpl
You can put your services and your controller traits anywhere you like in the project. You should put your controller object directly in the controllers package to make routing most convenient.

Related

How to inject parameters into a class/trait method in Scala

I have a code in my Play Scala (2.5x, 2.11.11) app which has been running just fine so far (it is based on the following link: https://fizzylogic.nl/2016/11/27/authorize-access-to-your-play-application-using-action-builders-and-action-functions/). But now I need to pass another class instance to ApplicationAuthorizationHandler class (NOTE: throughout my code I am using Guice DI for injecting parameters into class constructors).
Current code:
class ApplicationAuthorizationHandler
extends AuthorizationHandler {
...
}
trait AuthorizationHandler {
...
}
trait AuthorizationCheck {
def authorizationHandler: AuthorizationHandler = new ApplicationAuthorizationHandler
object AuthenticatedAction extends ActionBuilder[RequestWithPrincipal] {
override def invokeBlock[A](request: Request[A], block: (RequestWithPrincipal[A]) => Future[Result]): Future[Result] = {
def unauthorizedAction = authorizationHandler.unauthorized(RequestWithOptionalPrincipal(None, request))
def authorizedAction(principal: Principal) = block(RequestWithPrincipal(principal, request))
authorizationHandler.principal(request).fold(unauthorizedAction)(authorizedAction)
}
}
}
//Example controller using this trait AuthorizationCheck
class MyController #Inject() extends Controller with AuthorizationCheck {
def myAction = AuthenticatedAction { implicit request =>
...
}
Desired code:
class ApplicationAuthorizationHandler #Inject() (userService: UserService)
extends AuthorizationHandler {
...
// userService is used here
}
But since the instance of ApplicationAuthorizationHandler is instantiated inside trait AuthorizationCheck I can't inject UserService instance into it. I am Mixin this trait with all controllers so would like to keep the same way unless there is a better way (and there must be).
First, is there a way to inject directly into class/trait method ?
Alternatively, is there a way where I don't instantiate ApplicationAuthorizationHandler in trait AuthorizationCheck and pass it during run-time inside the controller ?
Or any other way ?
A trait does not need to provide an implementation, so you can have something like:
trait AuthorizationHandler {
...
}
class ApplicationAuthorizationHandler extends AuthorizationHandler {
...
}
trait AuthorizationCheck {
// just declaring that implementations needs to provide a
def authorizationHandler: AuthorizationHandler
object AuthenticatedAction extends ActionBuilder[RequestWithPrincipal] {
override def invokeBlock[A](request: Request[A], block: (RequestWithPrincipal[A]) => Future[Result]): Future[Result] = {
def unauthorizedAction = authorizationHandler.unauthorized(RequestWithOptionalPrincipal(None, request))
def authorizedAction(principal: Principal) = block(RequestWithPrincipal(principal, request))
authorizationHandler.principal(request).fold(unauthorizedAction)(authorizedAction)
}
}
}
// So, now this controller needs to provide a concrete implementation
// of "authorizationHandler" as declared by "AuthorizationCheck".
// You can do it by injecting a "AuthorizationHandler" as a val with
// name authorizationHandler.
class MyController #Inject()(val authorizationHandler: AuthorizationHandler) extends Controller with AuthorizationCheck {
def myAction = AuthenticatedAction { implicit request =>
...
}
}
And of course, you need to provide a module to bind AuthorizationHandler to ApplicationAuthorizationHandler:
import play.api.inject._
class AuthorizationHandlerModule extends SimpleModule(
bind[AuthorizationHandler].to[ApplicationAuthorizationHandler]
)
Of course, ApplicationAuthorizationHandler can have its own dependencies injected. You can see more details at our docs.
There are many cases when you cannot use the #Inject approach of guice. This is true when dependencies are needed inside of trait and also actors.
The approach I use in these cases is that I put my injector in a object
object Injector {
val injector = Guice.createInjector(new ProjectModule())
}
since the above is inside of an object, you can access it from anywhere. (its like a singleton).
Now inside your trait or an actor when you need the user service do
trait Foo {
lazy val userService = Injector.injector.getInstance(classOf[UserService])
}
Don't forget to make the variable lazy, because you want the instance to be created as late as possible when the injector has already been created.

How to mock an interface in Guice module with ScalaMock?

How can I simply mock an interface needed for injection in Guice using ScalaMock?
I've ended up using
import org.scalamock.MockFactoryBase
import org.scalatest.exceptions.TestFailedException
trait MyMockFactory extends MockFactoryBase {
type ExpectationException = TestFailedException
override protected def newExpectationException(message: String, methodName: Option[Symbol]): TestFailedException = ???
}
and in TestModule
class TestModule extends AbstractModule with MyMockFactory {
override def configure(): Unit = {
val mockObject = mock[ClassName]
bind(classOf[ClassName]).toInstance(mockObject)
}
}
Use a separate test module by binding mocked instances to class names and use that module to inject objects for your tests.
Test Module goes like this:
class TestModule extends AbstractModule {
override def configure(): Unit = {
val mockObject = mock[ClassName]
bind(classOf[ClassName]).toInstance(mockObject)
}
}
Spec goes like this:
class SomeSpec extends FlatSpec {
val injector = Guice.createInjector(new TestModule)
val mockObject = injector.getInstance(classOf[ClassName])
}

How to inject a trait with macwire

I have a Scala trait
trait UserRepository {
def findByEmail(email: String): User
}
I would like to inject this into a service with MacWire
class AccountService(){
val userRepo = wire[UserRepository]
}
And then use it in a test or class
class AccountServiceSpec {
val userRepo = new UserRepositoryImpl()
val accountSvc = new AccountService() //<--not manually injecting repo in service constructor
}
but I'm getting a compile error in the service class
Cannot find a public constructor nor a companion object for
accounts.repository.UserRepository
You may try to transform userRepo to class parameter, that allows macwire automatically provide its value for service:
import com.softwaremill.macwire._
case class User(email: String)
trait UserRepository {
def findByEmail(email: String): User
}
class AccountService(val userRepo: UserRepository)
class UserRepositoryImpl extends UserRepository{
def findByEmail(email: String): User = new User(email)
}
class AccountServiceSpec {
val userRepo = new UserRepositoryImpl()
val accountSvc = wire[AccountService] //<--not manually injecting repo in service constructor
}

How to inject services into actors using the Play 2.4?

I am able to inject services into my Application class with no issues. But somehow I am unable to inject into the actors themselves.
My actor:
class PollerCrow #Inject()(
#Named("pollService") pollService: PollService[List[ChannelSftp#LsEntry]]
, #Named("redisStatusService") redisStatusService: StatusService
, #Named("dynamoDBStatusService") dynamoDbStatusService: StatusService
) extends BaseCrow {
... impl and stuff ...
}
My actor's companion object:
object PollerCrow extends NamedActor {
override def name: String = this.getClass.getSimpleName
val filesToProcess = ConfigFactory.load().getString("poller.crow.files.to.process")
def props = Props[PollerCrow]
}
I'm getting the following when I run it:
IllegalArgumentException: no matching constructor found on class watcher.crows.PollerCrow for arguments []
How can I fix this?
Edit:
I have binded my actors:
class ActorModule extends AbstractModule with AkkaGuiceSupport {
override def configure() {
bindPollerActors()
}
private def PollActors() = {
bindActor[PollerCrow](PollerCrow.name)
}
}
Edit 2:
Additional details to the class:
abstract class BaseCrow extends Crow with Actor with ActorLogging
class PollerCrow #Inject()(
#Named(ServiceNames.PollService) pollService: PollService[List[ChannelSftp#LsEntry]]
, #Named(ServiceNames.RedisStatusService) redisStatusService: StatusService
, #Named(ServiceNames.DynamoDbStatusService) dynamoDbStatusService: StatusService
) extends BaseCrow {
override def receive: Receive = {
...
}
}
object PollerCrow extends NamedActor {
override def name: String = this.getClass.getSimpleName
def props = Props[PollerCrow]
}
trait NamedActor {
def name: String
final def uniqueGeneratedName: String = name + Random.nextInt(10000)
}
You might to make Guice aware of you actors. This is clean approach:
import com.google.inject.AbstractModule
import play.api.libs.concurrent.AkkaGuiceSupport
class ActorModule extends AbstractModule with AkkaGuiceSupport {
override def configure(): Unit = {
bindActor[YourActor]("your-actor")
}
}
#Singleton
class YourActor #Inject()(yourService: IYourService) extends Actor {
override def receive: Receive = {
case msg => unhandled(msg)
}
}
And application.conf:
play.modules {
enabled += "ActorModule"
}
For those who don't want to hassle, just call injector directly and don't forget to import Application to scope:
Play.application.injector.instanceOf[YourService]
Play.application.injector.instanceOf(BindingKey(classOf[YourService]).qualifiedWith("your-name"));

DI in Scala with Cake Pattern

This article explains Dependency Injection via Scala's Cake Pattern.
My understanding of this pattern's benefit is that traits can be mixed in (production v. test) with static checking.
In Mr. Bonér's example, he lists this finished (per example) code:
UserRepositoryComponent and UserServiceComponent
I added comments per my understanding.
trait UserRepositoryComponent {
val userRepository: UserRepository // stand-alone component
class UserRepository {
... // actual implementation here
}
}
trait UserServiceComponent {
this: UserRepositoryComponent => //Requires a mixed-in UserRepo*Component
val userService: UserService
class UserService {
... // actual implementation here
}
}
My understanding is that the Service depends on injection of a Repository component.
For production purposes, the following can be used to wire a "production" Repository component into the UserServiceComponent:
object ComponentRegistry extends
UserServiceComponent with
UserRepositoryComponent
{
val userRepository = new UserRepository
val userService = new UserService
}
If our production code wanted to use the userRepository or userService, is the correct way to use them via a simple import?
I think that I understand half of the article up to this point, but I'm not sure how to use the ComponentRegistry object.
You're running head first into the bakery of doom bro:
What are some compelling use cases for dependent method types?
To answer your question, the proper way to use userService would be to use another trait and cake it up:
trait Example { this: UserServiceComponent =>
def getExampleUser() = userService.getUser("ExampleUser")
}
Now whatever this new trait does isn't directly coupled to anything like the object ComponentRegistry. Instead your application becomes this:
object Application extends
Example with
UserServiceComponent with
UserRepositoryComponent
{
val userRepository = new UserRepository
val userService = new UserService
}
Anyway, you should run for the hills because if you really want to use cake you should be doing something more like this:
trait UserRepositoryComponent {
type UserRepository <: UserRepositoryLike
val userRepository: UserRepository
trait UserRepositoryLike {
def getUserOrSomething()
}
}
trait UserRepositoryComponentImpl extends UserRepositoryComponent {
type UserRepository = UserRepositoryImpl
val userRepository = new UserRepositoryImpl
class UserRepositoryImpl extends UserRepositoryLike {
override def getUserOrSomething() = ???
}
}
trait UserServiceComponent {
this: UserRepositoryComponent =>
type UserService <: UserServiceLike
val userService: UserService
trait UserServiceLike {
def getUserNameById(id: Int): String
}
}
trait UserServiceComponentImpl extends UserServiceComponent {
this: UserRepositoryComponent =>
type UserService = UserServiceImpl
val userService = new UserServiceImpl
class UserServiceImpl extends UserServiceLike {
override def getUserNameById(id: Int) = userRepository.getUserOrSomething
}
}
trait Example {
this: UserServiceComponent =>
def getExampleUser() = userService.getUserNameById(1)
}
object Application extends
Example with
UserRepositoryComponentImpl with
UserServiceComponentImpl
Now save yourself some time, drop the cake pattern, and do something simple.