Care for some juice? We have Google Guice
An interesting inversion-of-control framework has emerged under Google’s wing, built on Java 5 features, annotations and generics. The framework is called Guice, or Google Guice in full, and grew out of the needs of AdWords. Another interesting point is that Guice openly acknowledges the Spring Framework as an influence.
In Google Guice, relationships between objects are expressed entirely in code, through a dedicated API. The first building block is a module, which describes the basic mappings. The second is the annotation @Inject that tells the framework to inject a dependency.
Suppose we have a class Car, which uses an implementation of Engine, an interface that different types of engines can implement.
public class Car {
public Engine engine;
public void start(){
engine.start();
}
@Inject
public void setEngine(Engine engine) {
this.engine = engine;
}
}
public class BasicModule extends AbstractModule {
@Override
protected void configure() {
bind(Engine.class).to(EngineHDi.class);
}
}
From Guice’s point of view, a module, which extends a Guice class, uses the API to map an interface Engine to its implementation. In our case, EngineTDi. Car contains the annotation @Inject, which tells Guice to inject the mapped Engine implementation when it’s asked to create a Car.
To use Guice, of course, we have to initialize it and then request the class.
public class Main {
public static void main(String[] args) {
BasicModule module = new BasicModule();
Injector injector = Guice.createInjector(module);
Car car = injector.getInstance(Car.class);
car.start();
}
}
As you can see, code controls the whole IoC setup. There’s no need for XML. You don’t need special development extensions to manage the code, and features such as refactoring work smoothly in the IDE.
Now suppose we want Engine to have two different implementations (EngineTDi and EngineHDi) and to inject each according to some key. In Guice, an annotation can serve as that key.
To tell the engines apart, I decided to make the annotation @Octavia.
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD, ElementType.PARAMETER})
@BindingAnnotation
public @interface Octavia {
}
Now in the module’s mapping, I set Engine to use the implementation EngineTDi distinguished by the annotation @Octavia.
public class BasicModule extends AbstractModule {
@Override
protected void configure() {
bind(Engine.class).to(EngineHDi.class);
bind(Engine.class).annotatedWith(Octavia.class).to(EngineTDi.class);
}
}
To illustrate, I created the class Skoda, which extends Car. The important part of this class is the use of the annotation @Octavia, which, together with @Inject, tells Guice to create EngineTDiaccording to the mapping.
public class Skoda extends Car {
private Color color;
@Inject
public void setEngine(@Octavia Engine engine) {
this.engine = engine;
}
}
When we call Skoda skoda = injector.getInstance(Skoda.class); the IoC framework does indeed set EngineTDi.
Another feature is mapping constants. Let’s demonstrate it with our car example again. Take the enum Color.
public enum Color {
RED, BLUE, BLACK, WHITE;
}
We map an arbitrary color as a constant and have Guice inject it. To distinguish constants, we use an annotation, though we could also use the type.
public class BasicModule extends AbstractModule {
@Override
protected void configure() {
bind(Engine.class).to(EngineHDi.class);
bind(Engine.class).annotatedWith(Octavia.class).to(EngineTDi.class);
bindConstant().annotatedWith(RedColor.class).to(Color.RED);
}
}
Here’s the class Skoda extended to include a color. Guice again learns that it needs to inject a dependency from the annotation @Inject. The code shows that Guice can inject through any method, including methods that don’t follow the setter convention. You can annotate fields too, and Guice understands them.
public class Skoda extends Car {
private Color color;
@Inject
public void setEngine(@Octavia Engine engine) {
this.engine = engine;
}
@Inject
public void color(@RedColor Color color){
this.color = color;
}
public Color getColor(){
return color;
}
}
Guice has other features. I’ll mention a few briefly.
- Scopes. Each mapping can specify a singleton, one instance for every call, or a prototype, a new instance each time.
- Providers. Delegate object creation to a particular class acting as a factory. That’s useful when you can’t add annotations to code, for example with a third-party library.
- Lazy initialization. Objects aren’t initialized until the first request.
- Interceptors. Map an interceptor class to calls to methods carrying a given annotation.
Google Guice proudly calls itself a lightweight IoC framework, and it’s right. It’s genuinely simple and straightforward to use. If you’d like to compare it with Spring IoC, here’s a page from the Guice wiki, SpringComparison.
Guice is a breath of fresh air in my view, although Spring also supports configuration through annotations and code. See my presentation at CZJUG. One extra feature Spring offers is BeanPostProcessors, which let you modify a bean before the container exposes it. Of course, solutions for using Spring and Guice together will appear in the future, if they don’t exist already.
If you’re looking specifically for an IoC framework, Guice is worth trying and exploring. Pavel Kolesnikov offers another view on the revived Jablok in a suitably titled article, Google Guice.
You can download the source code for the examples above.
Related articles
Related articles
Related CZ Podcast episodes
- #3 · Java 6 SE, Vývoj webových aplikací
Dagi and Filemon discuss Java 6 and web application frameworks. · Czech audio
- #1 · Vývojová prostředí v Javě
The first CZ Podcast episode looks at Java development environments. · Czech audio