Play framework inherit dependency injected trait? - scala

Is it possible to create an overloaded play.api.mvc.Controller trait that has dependency injected arguments?
For example, say I have a couple of customized Actions that require a dependency injected AuthorizationService. I would like to write my controllers like this:
class UserController extends CustomController {
def getUser(userID: String) = CustomAction {
...
}
}
However, I can't figure out how to create the CustomController trait such that it doesn't require me to inject my AuthorizationService in my UserController. Is there a way to do this with Guice?

You can inject a field into your CustomController trait. The field should'n be final so it has to be declared as var in Scala.
#Inject() var authService: AuthorizationService
You can also make the injected var private and declare a public val which references the injected field. In this case val has to be lazy since injection occurs after class was instantiated. See Guice docs for more details.
#Inject() private var as: AuthorizationService = _
lazy val authService: AuthorizationService = as

It isn't possible to inject a dependency into a trait because a trait isn't instantiable. A trait doesn't have a constructor to define the dependencies, you must inject your AuthService via UserController
Example.
trait CustomController extends Controller {
val authService: AuthService
...
}
class UserController #Inject()(override val authService: AuthService) extends CustomController {
...
}

Related

Scala, cake pattern and mixins. How to avoid many parameters in "injected" class

While building a new Playframework app I am trying to use the cake pattern.
My first understanding was to mix custom traits into the controllers and pass those provided by Play as parameter:
trait MyComponents {
def actorSystem: ActorSystemClassic
lazy val service = new MyService(actorSystem)
}
class MyController(
controllerComponents: ControllerComponents,
override val actorSystem: ActorSystemClassic) with MyComponents {
// ...
// Use `service` from MyComponents
}
class MyApp extends BuiltInComponentsFromContext(context) {
val controller = new MyController(
controllerComponents, // <- Provided by BuiltInComponentsFromContext
)
}
That worked fine until I had to test MyController and tried to mock the service.
To mock the service I should be able to work with a stub of MyComponents that will provide the mock. To provide that stub I have to pass it as constructor parameter.
class MyController(
controllerComponents: ControllerComponents,
myComponents: MyComponents,
override val actorSystem: ActorSystemClassic) {
// ...
// Use `myComponents.service`
}
Of course my controller is more complex than that and he need more than one component to work. My fear is to end with a constructor that will become hardly manageable, with a lot of parameters.
To limit the number of parameters, one idea would be to mix all of the components in one. However I am not able to mix the instance on ControllerComponents provided by the super class BuiltInComponentsFromContext with MyComponents:
class MyController(components: MyComponents with ControllerComponents)
class MyApp extends BuiltInComponentsFromContext(context) {
val controller = new MyController(
new MyComponents with /*instance of controllerComponents provided by BuiltInComponentsFromContext*/
)
}
I do not want to pass the controllerComponents to MyComponents because that class provide business services, she don not care about controller components.
Can you help me to implement a real life application with the cake pattern ?

Access to protected var of Mock class

I'm using Mockito to test a scala class with a protected var. I would like to mock this var but obviously I can not access to this var via my mock class.
This is my code:
abstract class ETL_Generic(val fileCode: String, val rwSessionWrapper: RWSessionWrapper) extends Serializable {
protected var measurementsByFinalCode: scala.collection.Map[String, Measurement] = _
}
And this is the code to mock the abstract class:
val etlGenericMock = mock(classOf[ETL_Generic], withSettings().useConstructor("", rwSessionWrapperMock).defaultAnswer(CALLS_REAL_METHODS))
How can I assign a value to this var with the mock class?
Thanks.
I did an adapter extending the class to mock, overriding protected vars and then mocking this adapter.
Thanks!

How to handle circular dependency when using PlayFramework and Guice?

I'm using PlayFramework 2.6 with Scala and Guice and I have the following design between my components:
Some Person class objects:
#Singleton
class Person1 #Inject() (personApiService: PersonApiService, personDBApiService: PersonDBApiService) extends Person {
override def gerPersonInfo(person: Person): Future[PersonInfo] = {
...
}
}
I have few of those (Person1, Person2...).
In PersonService I need a list of the people instances so I did this:
Created a trait:
trait PeopleManager {
def application: Application
def peopleList = List(
classOf[Person1],
classOf[Person2],
...
)
lazy val peopleInstances: List[Person] = peopleList.map(personClass => application.injector.instanceOf(personClass))
}
So now I can do:
class PersonService #Inject() (val application: Application) extends PeopleManager {
// now I can use here peopleInstances.
}
The problem is, in my controller I get PersonService as dependency and I get to circular dependency. So in my controller I have to use Provider as suggested by PlayFramework documentation:
class MyController #Inject() (cc: ControllerComponents, peopleService: Provider[PersonServcie]) extends AbstractController(cc) {
...
}
This solved the circular dependency issue, but I have a problem now in my tests to create a mock for Provider[PersonService].
I feel something can be better in the design here that wont make me get circular dependency error, does someone have a nice suggestion?

Guice in Scala: Module for a class that has a DI-constructor itself

I'm using codingwell/scala-guice and trying to inject DAO-classes into constructors of other components/classes.
In the first attempt, I only used one DAO-class to see if it works:
class DaoModule extends AbstractModule with ScalaModule {
override def configure() {
val dao1 = new FirstDaoImpl
bind(new TypeLiteral[FirstDaoTrait] {}).toInstance(dao1)
}
}
The binding works as expected, it can be used for constructor injection.
In the second step, I wanted to add another DAO class to the module. However, that DAO-class depends on the first DAO:
class SecondDaoImpl #Inject()(firstDao: FirstDaoTrait) extends SecondDaoTrait
I'm not sure how to add the necessary binding to the existing module. Repeating the first step would result in this:
val dao2 = new SecondDaoImpl(???)
bind(new TypeLiteral[SecondDaoTrait] {}).toInstance(dao2)
But of course this class can only be instantiated by providing the first DAO (therefore the "???"). How can I do this?
Use bind and let scala-guice resolve the dependencies for you:
class DaoModule extends AbstractModule with ScalaModule {
override def configure() {
bind[FirstDaoTrait].to[FirstDaoImpl]
bind[SecondDaoTrait].to[SecondDaoImpl]
}
}
And now using the injector:
val injector = Guice.createInjector(new DaoModule())
val secondDao = injector.instance[SecondDaoTrait]

Cake pattern: how to get all objects of type UserService provided by components

This question may help you understand my needs.
Cake pattern: one component per implementation, or one component per trait?
I have a Scala application using multiple UserService implementations which will be provided by component(s?).
I wonder if there is a way in another component to "scan" the application so that I can retrieve a set of all components providing an object which implement the trait UserService?
So that I can iterate over all the UserService interfaces provided by my cake built application?
I guess I can have a component which build a list of UserService according to its dependency, but is it possible to have this component building the list without having any hardcoded dependency?
You can simply have a list of UserService instances right into UserServiceComponent, and have the base UserService register itself in this list.
trait UserServiceComponent {
private val _userServices = collection.mutable.Buffer[UserService]()
def userServices: Seq[UserService] = _userServices.synchronized {
_userServices.toList // defensive copy
}
private def registerUserService( service: UserService ) = _userServices.synchronized {
_userServices += service
}
trait UserService {
registerUserService( this )
def getPublicProfile(id: String): Either[Error, User]
}
val mainUserService: UserService
}
trait DefaultUserServiceComponent extends UserServiceComponent { self: UserRepositoryComponent =>
protected class DefaultUserService extends UserService {
// NOTE: no need to register the service, this is handled by the base class
def getPublicProfile(id: String): Either[Error, User] = userRepository.getPublicProfile(id)
}
val mainUserService: UserService = new DefaultUserService
}