I’ve always been a fan of Google Guice. More so lately, as Guice became an indispensable part of Bootique.io project, responsible for Bootique’s dependency injection (DI) and modularity. Guice is a simple, fun and powerful DI engine with a number of advantages over the industry status quo, yet there’s not a lot of guidance out there on its proper use compared to, say, Spring. To partially fill this gap I wrote a few of “stories”, each describing a coding or a design task, then going through Guice solutions, from the most obvious to the most optimal. Hope this will be useful to developers who use either Guice or Bootique. This post starts with two stories. More will follow.

Story 1: Injection Hygiene

This story is about basic injection. We assume some services have been already “bound” in Guice and we want to use them to write our own “service”. The simplest way to get a hold of another service is via field injection:

This is a quick and dirty approach. It is obvious why I am calling it quick: we declare an instance variable and annotate it with @Inject. Very little code. Why is it dirty though? Well, we ended up with a class that has a hard dependency on the injection container. There’s no way (short of ugly reflection) to create instances of A without Guice. So you won’t be able to write unit tests, etc. An obvious refactoring is to create a public constructor and use constructor injection:

Much better — now both Guice and our own code will be able to create instances of A. This is good enough and we can stop here, or we can perfect our solution a bit more. Notice that we still have a compile dependency on the @Inject annotation. I don’t know about you, but annotations on domain objects always look like code smell to me. Let’s refactor this to a pure object, moving the construction code into a “provider” method inside our Guice module:

We ended up with a bit more code, but this code is arguably higher quality than what we had initially. And in a real app with many DI-managed objects of some complexity such a trade-off will actually pay off.

There are other reasons as well why constructor injection may not be ideal and the provider approach can save us. Some objects can have too many dependencies, so the argument list becomes unwieldy. (Yes, I am aware of setter injection, but that breaks object immutability, so let’s not go there). Also many objects require complex initialization logic. Using provider methods (or custom Provider classes) as a default choice keeps you from a temptation to stick factory code inside the constructor, and thus greatly reduces domain object coupling.

Story 2: Open/Closed Principle for Modules

I think the Injection story was pretty straightforward. Now let’s talk a bit about modules and collections. If you’ve been using Guice, you are likely familiar with Multibinder and MapBinder that allow us to declare injectable maps and collections. What does it really give us? Let’s consider an example. Say we have an imaginary Command interface, and also an imaginary CommandExecutor that looks up a command by name and then executes it:

Let’s define a few commands and write a provider method for our executor:

This code will work. There’s one problem with it though. The module that defines CommandExecutor will need to know all the commands upfront. This violates “open/closed principle”, or in simpler terms it does not allow us to create a reusable module with CommandExecutor, deferring command definitions to app-specific downstream modules. Changing this code to use MapBinder to collect commands cleanly solves the reusability problem:

Here we replaced a hardcoded map with an injectable map that is initially empty. Also we created a static contributeCommands method that gives other modules a hint on how our reusable module can be extended. So downstream modules can add any number of commands that will all be available to the application.

This all sounds simple, but it is a very important design pattern. It turns our DI environment into a powerful modularity engine. Common algorithms can be “bound” in generic reusable modules, but the actual set of objects they operate upon is composed by all collaborating modules present in the app. “contribute*” methods comprise custom Module-level API, often the only thing we need to know about any given Module.

Conclusion

This concludes Part 1 of Guice stories. It is not a substitute for Guice documentation, but will hopefully answer some practical questions and will get you over the learning curve faster. More stories will follow shortly.

Follow me on Twitter.

ObjectStyle ; Open Source: ApacheCayenne, Agrest, Bootique, and more…

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store