Dependency injection in Play framework using Scala

This article is an overview of dependency injection (DI) techniques that can be used in Scala Play framework apps: Guice, manual DI, the cake pattern, MacWire, and the reader monad.

As a flexible framework, Play doesn’t force users to follow paths prepared by its designers. There are a lot of options to choose from when it comes to a dependency injection mechanism.

The default solution proposed by Play is JSR 330 with Guice implementation. In fact Play is DI‑agnostic – you can use various forms of compile time dependency injection, including the cake pattern and functional techniques, such as the reader monad. It may even sometimes be reasonable to mix different techniques. I’ll try to shortly describe some of the options that you have. Since some of the concepts described here are not really Play‑specific, they can be used in every Scala application.

The example application

The sections below contain descriptions of dependency injection mechanisms used in Scala Play applications. They all provide the same sample functionality.

The sample application exposes three HTTP endpoints: one that returns a list of books, one that returns a single book by its ID, and one that allows to update a book’s title. HTTP requests are handled by the
BooksController that depends on the
BooksService , which provides the data. Implementation of the
BooksService –
CachingBooksService depends on the
CacheApi component that is provided by Play. So, we’re going to see how to declare dependencies between components, define our own “injectable” component (
BooksService) and access a component provided by Play out of the box (
CacheApi).

The application is very simple, just to provide examples of DI usage, it has no HTML views. Play 2.5.0 and Scala 2.11 versions are used in the examples.

Here is the code that doesn’t use any DI yet, the dependencies are just declared as constructor parameters.

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

caseclassBook(id:Int,title:String)

objectBook{

implicitvaljsonFormat=Json.format[Book]

}

traitBooksService{

deflist:Seq[Book]

defget(id:Int):Option[Book]

defsave(book:Book):Unit

}

classCachingBooksService(cache:CacheApi)extendsBooksService{

privatevaldb=mutable.Map(

1->Book(1,"Twilight"),

2->Book(2,"50 Shades of Grey"))//simulates some persistent storage

overridedeflist:Seq[Book]={

//get "books" entry from cache, if it doesn't exist fetch fresh list from the "DB"

The default: Guice

JSR 330 approach is provided out of the box by Play, with default implementation being Guice library. Being both the default approach and runtime dependency injection, this technique requires the least effort for the programmer to configure. All components provided by the framework are ready to be injected. If you use the default router, you don’t have to bother with instantiating it, as the router has controllers automatically injected. You also don’t have to create custom application loader for this mechanism to work.

Defining components

You don’t have to explicitly declare that a given class is a component, so to create an injectable component simply create a class. If you want to (most likely you do) create components that implement an interface and make that interface injectable, you have to either use
@ImplementedBy annotation or define a module class.

1

2

3

4

5

6

7

8

9

10

11

12

importcom.google.inject.ImplementedBy

@ImplementedBy(classOf[ConcreteBooksService])

traitBooksService{

// ...

}

classConcreteBooksServiceextendsBooksService{

// ...

}

The approach taken in the above example requires the least effort but the existence of implementation‑class (
ConcreteBooksService) has to be known by the
BookService. Sometimes, the
BookService may come from an external library and you can’t annotate it. I’d say that it’s not a good practice to use
@ImplementedBy at all since it’s only supposed to define a default dependency, that can be overridden in the binding code.[1] Instead of
@ImplementedBy you can define a Guice module class:

1

2

3

4

5

6

7

8

9

10

11

12

importcom.google.inject.AbstractModule

importplay.api.{Configuration,Environment}

classGuiceModule(environment:Environment,configuration:Configuration)

extendsAbstractModule{

overridedefconfigure()={

bind(classOf[BooksService]).to(classOf[ConcreteBooksService])

}

}

Here, you bind
ConcreteBooksService as an implementation of a
BooksService. As you can see, the
GuiceModule class has access to an
environment and a
configuration , so you can bind different implementations depending on them.a To use this module, you have to enable it in your
application.conf using
play.modules.enabled configuration property:

1

2

3

play.modules.enabled+="modules.GuiceModule"

Depending on components

Using JSR 330 means using annotations from
javax.inject package. To declare a dependency on some component you can annotate class’ constructor with
@Inject:

1

2

3

4

5

6

classBooksController@Inject()(booksService:BooksService)

extendsController{

// ...

}

Constructor injection is not the only way to inject a dependency but setter-injection is a bad practice[2][3] , so I’ll just skip it.

As said before, APIs provided by Play are ready to be injected, so you can depend on them using
@Inject without any additional configuration:

1

2

3

4

5

6

classCachingBooksService@Inject()(cache:CacheApi)

extendsBooksService{

// ...

}

Summary

Using Guice has some advantages: it’s easy to configure, flexible, needs minimal boilerplate code and is supported out of the box by the framework. The main disadvantage is that it’s a runtime DI mechanism, what means that the compiler won’t detect component wiring problems. In some situations, you may get an error not only on application initialization but also later in the process of executing the logic.

For details about Guice itself, components scope and many other important topics see its excellent documentation.

The example application is implemented in the
guice module of the example project; see Running the examples chapter for more information about example code.

Do it yourself: The Manual DI

Dependency injection is about inverting the control – your components aren’t responsible for constructing dependencies, they have them injected instead. You may think it’s simpler to implement that because you don’t need any special constructs or libraries to achieve this. If your component classes declare their dependencies in constructor parameter list, you can create a module class and construct all the components manually:

1

2

3

4

5

6

7

classModule{

valcache:CacheApi=new// ...

valbooksService:BooksService=newCachingBookService(cache)

valbooksController:BooksController=newBooksController(booksService)

}

As you can see, the
Module class, once instantiated, has access to all components, and these components have their dependencies injected. In the application code, you access all the components using a
Module instance. The DI module, (aka an assembler) itself is not anything specific to the manual DI technique,[4] it’s a concept that every DI mechanism uses but some frameworks may hide its existence from the developer.

There is no special way to declare a dependency or a component, any class that provides a public constructor or a factory method can be made a component by instantiating it in the module. All Play components fulfil these criteria.

Manual DI in Play

To use a different DI technique than Guice, you need to create a custom
ApplicationLoader implementation. You have to wire all the components needed both for the Play itself and for your application code. Play helps you to achieve this by providing a
BuiltInComponentsFromContext abstract class.

In the above example, the
ApplicationModule class defines a DI module. It extends
BuiltInComponentsFromContext class that provides components needed by the framework itself, such as
Configuration and
HttpErrorHandler instances, and
EhCacheComponents trait that provides a cache implementation needed for
BookService. Later,
BooksService and
BooksController components are constructed. The router implementation cannot be provided by Play automatically in
BuiltInComponentsFromContext because it’s generated from
routes text file into the
router.Routes class – you have to construct it manually. As you can see, all dependencies must be both constructed and wired by yourself.

You may have noticed the usage of
lazyvals instead of regular
vals. If you use simple
val definitions, you may encounter
NullPointerExceptions if you forward-reference another field. Lazy definitions ensure correct initialization order, so you don’t have to worry about it but they come with a price – access to them must be synchronised.

To use the module, a custom application loader must be defined (
ApplicationLoader). To override Play’s default application loader, provide
play.application.loader configuration property in
application.conf and set it to fully qualified class name of the loader.

Summary

The manual DI’s advantage is mainly compile‑time wiring correctness verification. You can feel a bit safer when running your applications on top of it, compared to the Guice solution. Second good thing is that you don’t depend on any DI library. The bad thing is that you are required to construct and wire everything manually which can be a pain with a large number of components. For simple applications, Guice may be an overkill though, so manual DI is always worth considering.

The example application is implemented in the
manual module of the example project, see Running the examples chapter for more information about example code.

MacWire library – macros!

MacWire is a library that provides Scala macros that make manual DI much less painful. The concept is very similar to the manual DI but MacWire’s macros handle the wiring and check it, all at the compile time obviously. The library provides more than just macros, but in this article, I’ll focus on the core functionality that is macro-only.

Simplifying the manual DI

Remember the module definition from the chapter about the manual DI? Let’s rewrite it using MacWire:

1

2

3

4

5

6

7

8

9

classModule{

importcom.softwaremill.macwire._

valcache:CacheApi=// ...

valbooksService:BooksService=wire[CachingBookService]

valbooksController:BooksController=wire[BooksController]

}

As you can see, constructor invocations were replaced with
wire macro invocations. The macro resolves dependencies and expands to the code very similar to, or even the same, as the one from the manual DI chapter. If a dependency cannot be found, a compilation will fail with a descriptive message.

Using MacWire in Play

Because MacWire in its core functionality simplifies the manual DI, its usage in Play is very similar to the manual DI. You have to implement a custom application loader that will instantiate a DI module:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

importcontrollers.BooksController

importplay.api.BuiltInComponents

importplay.api.cache.EhCacheComponents

importservices.{BooksService,CachingBooksService}

importrouter.Routes

classApplicationLoader extendsplay.api.ApplicationLoader{

defload(context:Context)=newApplicationModule(context).application

}

classApplicationModule(context:Context)

extendsBuiltInComponentsFromContext(context)

withEhCacheComponents{

importcom.softwaremill.macwire._

lazyvalcache:CacheApi=defaultCacheApi

lazyvalbooksService:BooksService=wire[CachingBooksService]

lazyvalbooksController=wire[BooksController]

lazyvalrouter=wire[Routes]

}

One interesting thing in the above example is that the
cache field had to be declared in the
ApplicationModule class, even though
defaultCacheApi is already provided by
EhCacheComponents. This had to be done because
EhCacheComponents defines two members that have
CacheApi value – the
wire macro can’t decide by itself what value should be used when instantiating
CachingBooksService. By defining a field
cache we tell
wire to use the
defaultCacheApi.

Summary

MacWire is a nice library that has all the benefits of the manual DI but it helps a lot with the wiring. If you want a compile-time DI and you are not scared by macros messing with the code you wrote, then it’s a solid choice. Check out more about MacWire at its GitHub page.

The example application is implemented in
macwire module of the example project, see Running the examples chapter for more information about example code.

The cake pattern

The cake pattern is a popular compile-time dependency injection mechanism that uses Scala’s language features only to wire components. In this pattern, for each component you create, you need to implement a trait describing it. A DI module (aka cake) is created by “stacking” component traits, i. e. module class mixes in all the component traits. Play framework supports it by providing ready-to-use component traits. In contrast to the Guice solution, this DI technique requires much more boilerplate code and explicit configuration.

Defining components

The cake pattern comes in a couple of flavors. In the simplest form, a
BookService component with a dependency on a
CacheApi can be defined as follows:

In the above example we require that whenever a
BookServiceComponent trait is mixed in, the class which mixes it in has to implement a
CacheComponent trait. You can declare more dependencies by extending a self-type reference:

1

2

3

4

5

6

7

traitBookServiceComponent{

this:CacheComponent withOtherComponent=>

lazyvalbookService=newBookService(cacheApi,otherComponent)

}

A module definition would look as follows:

1

2

3

4

5

classModule

extendsCacheComponent

withBookServiceComponent

Then, when you instantiate a
Module class, all component instances inside the module will have their dependencies injected – it’ll just work by using language rules. You can obtain instances of all the components through the
Module instance.

Separating interfaces from implementations

In the real world, you normally would define an interface trait and implementations for your components. To achieve this with self-type cake pattern flavor you would do something similar to this:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

traitBookService{

// ...

}

traitBookServiceComponent{

defbookService:BookService

}

classCachingBookService(cache:cacheApi)extendsBookService{

// ...

}

traitCachingBookServiceComponentextendsBookServiceComponent{

this:CacheComponent=>

lazyvalbookService=newCachingBookService(cache)

}

If you use approach used in the above snippet, you can create components that depend on other components without the need of knowing anything about their concrete implementations:

1

2

3

4

5

6

traitBooksControllerComponent{

this:BookServiceComponent=>//dependency on any implementation of BookServiceComponent

// ...

}

Using the cake pattern in Play

The same as with the manual DI, you need to create a custom
ApplicationLoader implementation. Again,
BuiltInComponentsFromContext class helps you to provide core Play components to your cake.

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

importcontrollers.BooksControllerComponent

importplay.api.ApplicationLoader.Context

importplay.api.cache.EhCacheComponents

importrouter.Routes

importservices.CachingBooksServiceComponent

classApplicationLoader extendsplay.api.ApplicationLoader{

defload(context:Context)=newApplicationModule(context).application

}

classApplicationModule(context:Context)

extendsBuiltInComponentsFromContext(context)

withBooksControllerComponent

withCachingBooksServiceComponent

withEhCacheComponents{

lazyvalrouter=newRoutes(httpErrorHandler,booksController)

}

In the above example,
ApplicationLoader class is defined what instantiates a
ApplicationModule class serving as a cake.
BuiltInComponentsFromContext provides default implementations of internal Play components, such as
Application and
Configuration instances.
CachingBooksServiceComponent requires a cache implementation, so Play’s
EhCacheComponents trait is also mixed into the module. If you use the default router, the
Routes class is generated on compile‑time from a
routes file, so it cannot be made ready in
BuiltInComponentsFromContext – you have to instantiate it yourself.

Summary

Similarly to the manual DI, the cake pattern’s advantage is mainly compile‑time verification of the wiring, and no dependencies on external libraries. Component construction is manual but, contrary to the manual DI, wiring is automated by the Scala compiler. The bad thing is that this pattern requires you to write even more boilerplate code than the manual DI.

The example application is implemented in the
cake module of the example project, see Running the examples chapter for more information about example code.

The reader monad

“Wait, what is this thing?”

I intentionally left the reader monad as the last technique described to let you enjoy a nice long‑lasting aftertaste after reading the article. The reader monad is basically a monad for unary functions, that uses
Function1.andThen method as a monadic
map operation. If you don’t know what a monad is, don’t worry. If you use Scala or another functional language, you probably use it all the time anyway.

To understand what the reader is, first consider the following functions:

1

2

3

4

valsquare=(x:Int)=>x*x

valdivBy2=(x:Int)=>x/2.0

square function is
Int=>Int, and
divBy2 is
Int=>Double. You can chain them, what will create a new
Int=>Double function:

1

2

3

4

valchained=square.andThen(divBy2)

chained(3)//equal to divBy2(square(3))

The reader will turn your unary functions to monads, meaning that you can use
map and
flatMap methods on them. In turn that enables you to chain invocations in Scala’s
for comprehensions and do all the monady goodness. You can pretty easily craft your own reader implementation but you can also use one from the available libraries. I’ll use scalaz library in the example.

1

2

3

4

5

6

7

8

9

importscalaz.Reader

valsquare=Reader((x:Int)=>x*x)

valdivBy2=Reader((x:Int)=>x/2.0)

valchained=square.map(divBy2)

chained(3)// equivalent to divBy2(square(4))

The example above is analogous to the previous one but it uses readers instead of simple functions. Now look at this snippet:

1

2

3

4

5

6

7

8

9

10

importscalaz._

valsquareAndDivBy2Sum=for{

s<-square

d<-divBy2

}yields+d

sumSquareAndDivBy2(4)// equivalent to square(4) + divBy2(4)

The above example creates a reader that is equivalent to function

1

(x:Int)=>square(x)+divBy2(x)

by using a for comprehension. The for comprehension is just a syntactic sugar of

1

square flatMap(s=>divBy2 map(d=>s+d))

which may be more or less readable depending on a personal taste or one’s functional programming constructs familiarity level.

Unleash The Power of the Reader to do some DI

There are a couple of ways to declare a dependency. You can declare a dependency as a class’ constructor parameter, meaning that the whole class requires this dependency to work:

1

2

3

4

5

classBooksService(cache:CacheApi){

// ...

}

I took this approach in the previous chapters. Another possibility is to declare a dependency as a method parameter, and then, only methods that really require the dependency have it declared:

1

2

3

4

5

6

7

8

9

10

11

12

classBooksService{

defget(id:Int)(cache:CacheApi):Book={//this method has a dependency on the cache

// ...

}

defdoOtherThing(book:Book){//this method doesn't have a dependency on the cache

// ...

}

}

This is good because when there is a client that only wants to call
doOtherThing it doesn’t have to bother with the
CacheApi at all. Second good thing is that methods don’t have access to instances they don’t need access to. The downside is that this approach clutters method’s parameter lists. Marking method’s parameter list containing dependencies as
implicit can alleviate this cluttering problem but not solve it completely.

Both constructor injection and parameter injection require that when the method requiring a dependency is called by the client, the dependency is already instantiated and ready to use. This is different when using the reader monad. How to use the reader for the dependency injection? Let’s look at the following example:

1

2

3

4

5

6

7

8

9

10

11

classBooksService{

defget(id:Int)=Reader[CacheApi,Book]{cache=>

cache.getOrElse(id){

deffreshBook=fetchFreshBook(id)

cache.set(s"book$id",freshBook,2.minutes)

freshBook

}

}

}

As you can see, the
get method doesn’t declare a dependency as one of its parameters, it declares it in a return type. It doesn’t return a
Book, it returns the reader that accepts the dependency (
CacheApi) and returns a
Book. So when a client code calls the service with
service.get(1) it doesn’t get the
Book instance right away – it gets the reader that can return the value when you provide it the required dependency – in this case, an instance of
CacheApi.

1

2

3

4

valbookReader=service.get(4)//get the reader

valbook=bookReader.run(cache)//read the value by providing the dependency

The above snippet can be shortened to:

1

2

3

valbook=service.get(4)(cache)

The advantage is that you can combine the reader that is returned by
service.get(4) with other readers, do some transformations, and finally provide all the dependencies to get the result.

What your mom didn’t tell you

Some people argue that the reader monad can replace the functionality of other dependency injection mechanisms. I say that’s not entirely true. While the reader monad is a great functional tool, in my opinion, if used as a DI technique, it performs best in conjunction with object-oriented DI mechanisms. The problem is that when you declare dependencies in method signatures, as it is done with the reader monad, you can’t separate dependencies of concrete component implementations from their interfaces. Take a look at the following example:

1

2

3

4

5

6

7

8

9

10

11

traitBooksService{

defget(id:Int):Book

}

classCachingBooksServiceextendsBooksService{

overridedefget(id:Int)=Reader[CacheApi,Book]{

// ...

}

}

Obviously, this won’t compile because
CachingBooksService.get method’s return type is not compatible with
BooksService.get method’s return type. Normally, you’d want to hide the dependency on
CacheApi from
BooksService clients, which is impossible to do with the reader monad approach. My take on this is to use other object-oriented DI mechanism, and complement it with the reader monad where possible.

The great thing about the reader monad is that it can be used in components that are not managed in any way by any DI framework, so it can be for example used in the domain layer, avoiding so-called anemic domain model.[5][6] In the above example, it’s been used in
Book case class and its companion object. The
BooksController has the service injected by Guice. Pay special attention to the
updateTitle method. It uses
save and
get methods without providing the service right away which looks pretty clean because you don’t have to clutter your logic by providing the dependencies. This is a big advantage in the real-world scenario, when you have to work with many dependencies, results from many components, chain invocations, and transform results. The value is demanded from the reader by invoking
run or
apply method that provides a dependency. Normally, the logic of
updateTitle probably shouldn’t be defined in the controller but you get the idea.

Summary

The reader monad is a special DI mechanism in the sense that it’s not object oriented technique but it is functional. As a DI technique, it fits well in Scala, a language that combines object-oriented and functional worlds, allowing you to use the reader monad in conjunction with other dependency injection styles.

The example application is implemented in the
reader module of the example project, see Running the examples chapter for more information about example code.

Conclusion

I hope that this article managed to provide an overview of some dependency injection techniques and how to use them in applications based on the Play framework. There certainly is no silver bullet when it comes to choosing a DI mechanism. My personal favourite is MacWire combined with the reader monad. I consider the cake pattern too bloated and I reject Guice because it works at runtime. It’s good to have freedom of choice, and this is what the Play framework gives you.

Running the examples

The source code of all example applications is available on GitHub here. The easiest way to run the applications is to clone the git repository and use sbt. If you work with Play, you probably already have sbt installed. If not then follow the instructions on the sbt website.

If you have never worked with Play before, downloading all the dependencies may take several minutes. After the command completes, the application should be available at http://localhost:9000. The application is not a big deal, but you can experiment with the code, modify it and just refresh the page – sbt will recompile necessary files and reload the application automatically.

Notes

a. It may actually be better to define multiple modules instead of embedding logic in the module[7]

It is very nice article, I have the following point. The Reader example add one layer of indirection to hide Reader monad from service traits. The same can be done for multiple parameter lists where it was mentioned as their disadvantage. I would argue that disadvantage of Reader approach is that it locks you into Reader monad. While monads provide map and flatMap for composition they after all don’t compose that well because only monads of the same type compose. Hence it is then Reader monad top-down or more advanced techniques like monad transformers has to be introduced at some point.

On the other hand method with multiple parameter lists can be lifted to Reader monad only when needed on call site, using partial application which results in BookService => Option[Book] function (Reader { get(id)(_) }.

With multiple parameter lists it becomes (I haven’t test it, but I think it is equivalent to Reader example but I could miss some detail):

Based on it the Reader pattern is not convincing for me at least based on the given example, some more flatMaped composition would have to be need it to show its beauty. Multiple parameter lists seem easier to me and more flexible (can lift them to Monad).

It should be possible to make second parameter list implicit to let compiler wire it up automatically (similarly like @Autowire does but still compile time).

Another point was not immediately apparent to me even it is implicitly mentioned in “so it can be for example used in the domain layer, avoiding so-called anemic domain model”. In traditional OOP common code would be in BooksService. But in case of Reader monad and my example with multiple parameter lists it goes to Book domain model, e.g. common code can be placed before and after service.get(id) call in Book. Maybe it could help to make it more apparent by placing some comments, or discuss it in the article. I believe it is significant difference which doesn’t have to be clear immediately from rich vs. anemic domain model, depending how much developer is versed in these terms. Otherwise reader can be asking for what that additional manual wiring is good for.

Using Reader monad is convincing if this, as written in the article, is the main goal. Provided examples don’t show this capability.
“The advantage is that you can combine the reader that is returned by service.get(4) with other readers, do some transformations, and finally provide all the dependencies to get the result.”