Inject a list of objects to play application context - scala

In my project I have bunch of animal objects, for example:
some of them have dependency injection:
class Monkey #Inject() (wsClient: WSClient, configuration: Configuration) extends Animal {
...
}
and some not:
class Giraffe extends Animal {
...
}
In my AnimalsService class I need a list of all the animal objects instances,
Currently my service is getting the list of people as a dependency injection:
class AnimalsService #Inject() (animals: List[Animal]) {
// here I can use animals as my desire
}
and then I have a binding class that bind it:
class Bindings extends AbstractModule {
override def configure(): Unit = {
bind(classOf[AnimalsService]).toProvider(classOf[AnimalServiceProvider])
}
}
object Bindings {
class AnimalServiceProvider #Inject () (giraffe: Giraffe, monkey: Monkey ...) extends Provider[AnimalsService] {
override def get: AnimalsService = {
new AnimalsService(List(giraffe,monkey...))
}
}
}
This works perfectly, but what I would prefer is to have somehow to add the list to my application context as the app loads so I don't need to do it this way....
This current solution also means I need to add new animals to AnimalServiceProvider constructor and to here new AnimalsService(List(giraffe,monkey...)) every time I need a new animal, and that will be happened constantly...
What will be the best way of handling this kind of situation?
I thought maybe using #Named annotation of guice but not sure if its the right way or how to name a list of objects this way...

I would do a Singleton bean that has the list and a method to add definitions
class AnimalsService #Inject() () {
val animals: List[Animal]
def addAnimal(animal: Animal) {
....
}
// here I can use animals as my desire
}
Then in each module that needs an animal would need an extra singleton with Eager bindings
class MonkeyConfigurator #Inject() (animalsService: AnimalsService) extends Animal {
animalsService.add(this) //Or anything
// here I can use animals as my desire
}

Related

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?

Scala Guice - inject with a mixin

Is it possible to instantiate the dependency first and then bind it in the module config method?
Currently I have the following config:
class PersonServiceImpl #Inject()(addressService: AddressService) {
...
}
class AppModule extends AbstractModule with ScalaModule {
def configure() {
bind[PersonService].to[PersonServiceImpl]
bind[AddressBook].to[AddressBookImpl]
}
#Provides #Singleton
def provideAddressService(addressBook: AddressBook): AddressService = {
new AddressServiceImpl(addressBook) with SecureAddressView
}
}
... which works fine. What I want to do now is to move the instantiation of the AddressServiceImpl into a separate module. So, the problem is that in order to create an instance of AddressServiceImpl I need Guice to inject the addressBook parameter for me, but I also want to create the instance myself so I can mix SecureAddressView in:
class AddressModule extends AbstractModule with ScalaModule {
def configure() {
bind[AddressService].to[AddressServiceImpl]
}
#Provides #Singleton
def provideAddressService(addressBook: AddressBook): AddressService = {
new AddressServiceImpl(addressBook) with SecureAddressView
}
}
This fails, though, as Guice comes back complaining about the provideAddressService method. It basically says that A binding to AddressService was already configured and points to the bind[AddressService].to[AddressServiceImpl] line in the configure method.
Any idea how to create an instance and mix in a trait while still delegating the resolution of downstream parameter dependencies to Guice?
OK, quite an obvious one but I was misled by the fact that I had to override the configure method. So, all I had to do is provide a dummy implementation for configure.
class AddressModule extends AbstractModule with ScalaModule {
override def configure(): Unit = ()
#Provides #Singleton
def provideAddressService(addressBook: AddressBook): AddressService = {
new AddressServiceImpl(addressBook) with SecureAddressView
}
}
Although this still looks quite dodgy as I have to provide explicitly all the parameters to the AddressService constructor. There must be a more elegant way of mixin traits. Or maybe not...

Scala traits exposing protected members?

Given a class like:
class MyClass {
protected object MyObj { ... }
}
is it possible to write a trait that will permit exposing MyObj. E.g. with inheritance I could do the following:
class TestMyClass extends MyClass {
val getMyObj = MyObj
}
but I want to do this via a trait, something like the following which doesn't typecheck:
trait ExposeMyObj {
val getMyObj = MyObj // super.MyObj/this.MyObj don't work
}
and use it like:
class TestMyClass extends ExposeMyObj
Is it possible to reproduce the functionality in TestMyClass into a trait to expose the protected object, and if so how?
If you know that your trait will always be mixed in to an instance of MyClass (or a subclass), you can enforce the expectation with a self-type, and then access the object:
trait ExposeMyObj {
self: MyClass =>
val getMyObj = MyObj
}
Edit: an example of using this trait:
class TestMyClass extends MyClass with ExposeMyObj
val test = new TestMyClass
test.getMyObj // accesses MyObj defined in MyClass.
Edit 2: attempting to address #jbrown's comment (re: testing queries within repos) - I would look at doing something like the following - first, in each repo's file, add a trait for each repo holding the queries for that repo:
trait UserQueries { // you could look at making this protected, if you like
protected def query1(param: String) = List(param) // very silly implementation, but hopefully enough to make the point
... // other queries
}
class UserRepo extends UserQueries // Has (internal) access to those queries
Then in the test class file for a given repo:
class UserQueriesTester extends UserQueries with ScalaTest { // or whatever test framework you are using
// (public) tests to run - eg:
def testQuery1 = query1("test") should be (List("test"))
}

Scala Slick Cake Pattern: over 9000 classes?

I'm developing a Play! 2.2 application in Scala with Slick 2.0 and I'm now tackling the data access aspect, trying to use the Cake Pattern.
It seems promising but I really feel like I need to write a huge bunch of classes/traits/objects just to achieve something really simple. So I could use some light on this.
Taking a very simple example with a User concept, the way I understand it is we should have:
case class User(...) //model
class Users extends Table[User]... //Slick Table
object users extends TableQuery[Users] { //Slick Query
//custom queries
}
So far it's totally reasonable. Now we add a "Cake Patternable" UserRepository:
trait UserRepository {
val userRepo: UserRepository
class UserRepositoryImpl {
//Here I can do some stuff with slick
def findByName(name: String) = {
users.withFilter(_.name === name).list
}
}
}
Then we have a UserService:
trait UserService {
this: UserRepository =>
val userService: UserService
class UserServiceImpl { //
def findByName(name: String) = {
userRepo.findByName(name)
}
}
}
Now we mix all of this in an object :
object UserModule extends UserService with UserRepository {
val userRepo = new UserRepositoryImpl
val userService = new UserServiceImpl
}
Is UserRepository really useful? I could write findByName as a custom query in Users slick object.
Let's say I have another set of classes like this for Customer, and I need to use some UserService features in it.
Should I do:
CustomerService {
this: UserService =>
...
}
or
CustomerService {
val userService = UserModule.userService
...
}
OK, those sound like good goals:
Abstract over the database library (slick, ...)
Make the traits unit testable
You could do something like this:
trait UserRepository {
type User
def findByName(name: String): User
}
// Implementation using Slick
trait SlickUserRepository extends UserRepository {
case class User()
def findByName(name: String) = {
// Slick code
}
}
// Implementation using Rough
trait RoughUserRepository extends UserRepository {
case class User()
def findByName(name: String) = {
// Rough code
}
}
Then for CustomerRepository you could do:
trait CustomerRepository { this: UserRepository =>
}
trait SlickCustomerRepository extends CustomerRepository {
}
trait RoughCustomerRepository extends CustomerRepository {
}
And combine them based on your backend whims:
object UserModuleWithSlick
extends SlickUserRepository
with SlickCustomerRepository
object UserModuleWithRough
extends RoughUserRepository
with RoughCustomerRepository
You can make unit-testable objects like so:
object CustomerRepositoryTest extends CustomerRepository with UserRepository {
type User = // some mock type
def findByName(name: String) = {
// some mock code
}
}
You are correct to observe that there is a strong similarity between
trait CustomerRepository { this: UserRepository =>
}
object Module extends UserRepository with CustomerRepository
and
trait CustomerRepository {
val userRepository: UserRepository
import userRepository._
}
object UserModule extends UserRepository
object CustomerModule extends CustomerRepository {
val userRepository: UserModule.type = UserModule
}
This is the old inheritance/aggregation tradeoff, updated for the Scala world. Each approach has advantages and disadvantages. With mixing traits, you will create fewer concrete objects, which can be easier to keep track of (as in above, you only have a single Module object, rather than separate objects for users and customers). On the other hand, traits must be mixed at object creation time, so you couldn't for example take an existing UserRepository and make a CustomerRepository by mixing it in -- if you need to do that, you must use aggregation. Note also that aggregation often requires you to specify singleton-types like above (: UserModule.type) in order for Scala to accept that the path-dependent types are the same. Another power that mixing traits has is that it can handle recursive dependencies -- both the UserModule and the CustomerModule can provide something to and require something from each other. This is also possible with aggregation using lazy vals, but it is more syntactically convenient with mixing traits.
Check out my recently published Slick architecture cheat sheet. It does not abstract over the database driver, but it is trivial do change it that way. Just wrap it in
class Profile(profile: JdbcProfile){
import profile.simple._
lazy val db = ...
// <- cheat sheet code here
}
You do not need the cake pattern. Just put it all in one file and you get away without it. The cake pattern allows you to split the code into different files, if you are willing to pay the syntax overhead. People also use the cake pattern to create different configurations including different combinations of services, but I don't think this is relevant to you.
If the repeated syntax overhead per database table bothers you, generate the code. The Slick code-generator is customizable exactly for that purpose:
If you want to blend hand-written and generated code, either feed the hand-written code into the code-generator or use a scheme, where the generated code inherits from hand-written cor vise-versa.
For replacing Slick by something else, replace the DAO methods with queries using another library.

Using Scala companion object as factory by extending a factory trait. Better solution?

Scala companion objects are frequently proposed as object factories. They seem to work well for this in the production code, but what about inserting mock objects for testing? The companion object won't know about the mock object and therefore cannot instantiate it.
I'd like to do something like this:
class Foo {}
object Foo {
def create():Foo = new Foo()
}
class FooCreator(factory:Foo) {
def this() = this(Foo)
...
factory.create()
...
}
class FooMock extends Foo {}
object FooMock extends Foo {
def create():Foo = new FooMock()
}
// in a test
val fooCreator = new FooCreator(FooMock)
This won't work because a companion object cannot be extended. I'm forced to create a Factory trait for both companion objects to mixin:
trait FooFactory {
def create():Foo;
}
class Foo {}
object Foo extends FooFactory {
def create():Foo = new Foo()
}
class FooCreator(factory:FooFactory) {
def this() = this(Foo)
...
factory.create()
...
}
class FooMock extends Foo {}
object FooMock extends FooFactory {
def create():Foo = new FooMock()
}
// in a test
val fooCreator = new FooCreator(FooMock)
Is there a better way to do this? Creating the factory trait just feels wrong, since that's what the companion object is supposed to be good at. (Keep in mind that the Mock artifacts are only known to the test subsystem, so I can't solve the problem by letting object Foo create a FooMock instance - the common pattern in production code).
Use the apply method rather than the object as your factory, as detailed in the answers to my question How to use companion factory objects as strategy?
You might want to take a look at ScalaMock, a mocking framework for Scala that can (among other things) mock object creation (compiler invocation). This is exactly one of the problems it's intended to solve.