Conditional injection with scala play and guice

It’s been a crazy year for me. For those who don’t know I moved from the east coast to the west coast to work for a rather large softare company in seattle (I’ll let you figure which one out) and after a few short weeks realized I made a horrible mistake and left the team. I then found a cool job at a smaller .net startup that was based in SF and met some awesome people and learned a lot. But, I’ve been poached by an old coworker and am now going to go work at a place that uses more open source things so I decided to kick into gear and investigate scala and play.

For the most part I’m doing a mental mapping of .NET’s web api framework to the scala play framework, but the more I play in play (pun intended) the more I like it.

On one of my past projects a coworker of mine set up a really interesting framework leveraging ninject and web api where you can conditionally inject a data source for test data by supplying a query parameter to a rest API of “test”. So the end result looks something like:

The way it chose the correct data provider is by leveraging a custom parameter binder that will resolve the source from the ninject kernel based on the query parameters. I’ve found that this worked out really well in practice. It lets the team set up some sample data while testers/qa/ui devs can start building out consuming code before the db layers are even complete.

I really liked working with this pattern so I wanted to see how we can map this to the scala play framework. Forgive me if what I post isn’t idiomatic scala, I’ve only been at it for a day :)

It should be pretty clear whats going on here. I’ve defined two classes that implement the data source trait. Which one that gets injected should be defined by a query parameter.

Guice lets you define bindings for the same trait (interface) to a target class based on “keys”. What this means is you can say “give me class A, and use the default binding“, or you can say “give me class A, but the one that is tagged with interface Test“. When you register the classes you can provider this extra tagging mechanism. This is going to be useful because you can now request different versions of the interface from the binding kernel.

Lets just walk through the remaining example. First we need the interface, but Guice wants it to be an annotation. Since scala has weird support for annotations and the JVM has shitty type erasure, I had to write the annotation in java

What this is saying is that given the 3 types (the main interface, the implementation of the main item, and the implementation of the dev item) to conditionally bind the dev item to the marker class of “TestAnnotation”. This will make sense when you see how its used.

As normal, guice is used to set up the controller instantation with the source module registered.

The kernel never has to be registered since Guice will auto inject it when its asked for (its implicity available). Whats happening here is that we set up the kernel and the target interface type we want to get (i.e. DataSource). If the query string matches the sourceable query param toggle (i.e. the word “test”) then it’ll pick up the registered data source using the “test annotation” marker. Otherwise it uses the default.