Introduction to Google Guice

1) Introduction

Google Guice is a Dependency Injection Framework that can be used by Applications where Relation-ship/Dependency between Business Objects have to be maintained manually in the Application code. Since Guice support Java 5.0, it takes the benefit of Generics and Annotations thereby making the code type-safe. This article provides an overview about the Guice framework with a lot many samples. It then looks into the theories related to Dependency Injection Framework and the advantages of using them in Application. It also explores the various API available in Guice along with the Annotations that simplifies most of the things. The final section presents lots of samples thereby making most of the Guice API to get a much better feel towards the API.

2) Dependency Injection

Since Guice is a Dependency Injection Framework, let us make a clear understanding on Dependency Injection which is gaining more popularity in the recent years and a much needed mechanism to be followed in a typical Application. To name a few, J2EE 5.0, Spring, JBoss Seam are good examples that makes use of Dependency Injection. Now, let us take a simple example to illustrate the need for a Dependency Injection Framework.
Consider the following scenario. A Storage represents some kind of repository for storing any type of data. If someone asks us to model the (simple) Class Diagram for this kind of situation, then we could have come up with a design very similar to the one mentioned below.
Storage.java

interface Storage{

    public void store(String uniqueId, Data data);
    public Data retrieve(String uniqueId);

}

The above interface provides a mechanism to store and retrieve Data through its store() and retrieve() methods. Since Data can be stored in a Database or even a File, concrete implementations for the above interface may look something like the following.
FileStorage.java

class FileStorage implements Storage{

    public void store(String uniqueId, Data data){
        // Store the object in a file using Java Serialization mechanism.
    }

    public Data retrieve(String uniqueId){
        // Code to retrieve the object.
    }

}

The FileStorage implementation class may store and retrieve Data in a file which is present in a hard disk. Following is another implementation for the Storage interface where every information is stored in a Database.
DatabaseStorage.java

class DatabaseStorage implements Storage{

    public void store(String uniqueId, Data data){
        // Open a connection and store the data.
    }

    public Data retrieve(String uniqueId){
        // Get the data from the Database.
    }

}

Now, let us look into a Sample Client Application that makes use of this Client. Following is the Client code snippet which initially makes use of FileStorage implementation and then switches over to DatabaseStorage implementation.
StorageClient.java

public class StorageClient {

    public static void main(String[] args) {

        // Making use of file storage.
        Storage storage = new FileStorage();
        storage.store("123", new Data());

        // Making use of the database.
        storage = new DatabaseStorage();
        storage.store("456", new Data());
    }
}

Note the code in the Client module carefully. Even though, the interface and the implementation classes enjoys loose coupling, the Client module has to manually create instances to the actual implementation classes. Also the relation-ship between the interface and the implementation classes is maintained directly in the Client code. Since, in most of the cases, during the compilation time itself, the Client Application knows to which implementation classes the corresponding interfaces will bound to, will it be useful if someone takes care of maintaining everything. That’s what Google Guice does. It takes creating instances in the form of Services from the Application client code and the Dependency between the Clients to its Services is automatically injected through some easy Configuration Mechanism. Following section will provide a simple example that makes use of Guice Framework.

3) Writing the first simple Guice Example

In this very simple example, let us see how Guice simplifies Development life in maintaining the Relation-ship/Dependency between objects. Let us have a look into the following code snippet. Following is the code for the traditional Add interface which defines a method called add() which is to be given implementation by some other class.
Add.java

package add.service;

public interface Add {

    public int add(int a, int b);

}

This is the class implementing the Add interface which merely returns the sum of two numbers.
SimpleAdd.java

package add.service;

public class SimpleAdd implements Add{

    public int add(int a, int b) {
        return a + b;
    }

}

This is the Module class which makes use of Guice API to establish Bindings in an Application. Theories towards Module and Bindings are covered in detail in the subsequent sections. For now, just consider that a Module can be configured with some of Bindings which is done through the Binder class. In Guice terms, a Binding refers to the process of providing association to an Interface to its original Implementation.
AddModule.java

package add.service;

import com.google.inject.Binder;
import com.google.inject.Module;

public class AddModule implements Module{

    public void configure(Binder binder) {
        binder.bind(Add.class).to(SimpleAdd.class);
    }

}

In the above code, we are telling Guice to bind the implementation for Add interface to SimpleAdd class which literally tells that calls on Add.add() made by the clients will be re-directed to SimpleAdd.add(). Following is the Client code which uses this Add interface.
AddClient.java

package add.service;

import com.google.inject.Guice;
import com.google.inject.Injector;

public class AddClient {

    public static void main(String[] args) {

        Injector injector = Guice.createInjector(new AddModule());
        Add add = injector.getInstance(Add.class);
        System.out.println(add.add(10, 54));
    }
}

More theories towards Injector, Guice are yet to come in the subsequent sections. Injector.getInstance(Add.class) will now create and return an instance of type SimpleAdd. Note the concrete implementation class gets bound in the AddModule.configure() method.

4) Exploring the Guice API

Let us explore the various API that makes up the Dependency Injection in Guice. More specifically the following Interfaces/Classes are covered in this section.

  • Binder
  • Injector
  • Module
  • Guice

4.1) Binder

This interface mainly consists of information related to Bindings. A Binding refers a mapping for an Interface to its corresponding Implementation. For example, considering the above example, we refer that the interface Add is bound to SimpleAdd implementation.
Programatically, it is can be mentioned as follows. Note that the class object for both the interface and the implementation classes is passed on to the bind() and the to() methods.

binder.bind(Add.class).to(SimpleAdd.class)

It is also possible to bound an Interface directly to its Instance as the following code suggest that.

binder.bind(Add.class).to(new SimpleAdd())

The third variation is to bind the Interface to its corresponding Provider class. By default, it is the Guice Framework which will instantiate and return objects needed by the Application. But, what if the Object Creation Process needed customization? Providers simply do that. Simply put, Providers follows the traditional Factory Pattern in creating objects. For example, consider the following code snippet,

binder.bind(Add.class).to(new AddProvider())

We will provide you samples on how to create Provider objects. For the time being, just keep a note that, in some way the AddProvider class provides Factory methods that will return objects of type Add.
It is also possible to bind an Interface to multiple implementations which will be covered in the later sections.

4.2) Injector

Injectors take care of creating and maintaining Objects that are used by the Clients. Injectors do maintain a set of Default Bindings from where they can take the Configuration information of creating and maintaining Relation-ship between Objects. Consider the following code snippet which will return some implementation of type Add.

Add addObject = injector.getInstance(Add.class)

To get all the Bindings associated with the Injector, simply make a call to Injector.getBindings() method which will return a Map of Binding objects.

Map<Key, Binding> allBindings = injector.getBindings()

Note that every single Binding often has a corresponding Key object which is internally created and maintained by Guice. Providers, if any, which are associated with the Injector can be retrieved by the following method.

Provider provider = injector.getProvider(SomeType.class)

4.3) Module

Modules are objects which will maintain the set of Bindings. It is possible to have multiple Modules in an Application. Injectors, in turn, will interact will the Modules to get the possible Bindings. Module is represented by an interface with a method called Module.configure() which should be overridden by the Application to populate the Bindings. To simplify things, there is a class called AbstractModule which directly extends the Module interface. So Applications can depend on AbstractModule rather than Module.
Consider the following code snippet,
MyModule.java

class MyModule extends AbstractModule{

    public void configure(Binder binder){

        // Code that binds information using the various
        // flavours of bind method.
    }
}

4.4) Guice

Guice is a class which Clients directly depends upon to interact with other Objects. The Relation-ship between Injector and the various modules is established through this class. For example consider the following code snippet,

MyModule module = new MyModule();
Injector injector = Guice.createInjector(module);

Note that Guice.createInjector() method is passed with a Module Object. Module class must have an overridden method called configure() which is passed with a Default Binder object. This Binder object populates the various Bindings (to Classes, Objects and Providers) that are specific to an Application. Now when a Client requests for an Instance by invoking the getInstance() of the Injector class, Injector in turn will look into the various Bindings maintained by the Binder object to get the original object.

5) Guice Annotations

Guice comes with a small set of useful Annotations that are used to add meta-data values to an Application. Following are the Annotations that are going to get covered in this section.

  • Implemented By
  • Inject
  • Provided By
  • Singleton

5.1) Implemented By

This Annotation points to a Class object that provides Implementation to the interface. For example if the Add interface has multiple implementations and if we wish to have SimpleAdd as the default implementation, then we can say like the following,
Add.java

@ImplementedBy(SimpleAdd.class)
interface Add{

    public int add(int a, int b);

}

5.2) Inject

For injecting instances directly to the Client code, we can use this Inject Annotation. This annotation can be used in a Constructor for a class, for a method or for a Field. For example, consider the following example,
Client.java

class Client{

    @Inject
    public Client(MyService service){
    }
}

The above is an example for Constructor-level Injection assuming that the concrete implementation for the MyService interface would have got bounded by defining them in some Application specific Module. The same applies for Method-level and Field-level Annotations.

5.3) Provided By

Assuming that we want to customize the Object creation process for some interface type, then we would depend on Guice Provider mechanism. Let’s say, for Add interface we want AddProvider to create and return objects of type SimpleAdd. In such a case, we can qualify what is the Provider type for the Interface by directly annotating it in the Interface declaration. Consider the following code snippet,
Add.java

@ProvidedBy(AddProvider.class)
public interface Add{

}

5.4) Singleton

By default, when a Client request for Objects by calling Injector.getInstance() multiple times, every new instance is created and returned. If we want to restrict this number by returning one and only instance for the class (which is the Singleton Pattern), the implementation classes can be marked with Singleton Annotation.
MyConnection.java

@Singleton
public class MyConnection{

    public void connect(){
    }

    public void disconnect(){
    }
}

6) Samples

6.1) Introduction

This section will provide you plenty of sample Applications that makes use of various Guice API. Let us explore them in much detail.

6.2) Simple Example

This simple example demonstrates the usage of Guice where we don’t have a separated Interface and Implementation. All we have is a concrete Implementation class and Clients directly depend on them. Though Guice doesn’t do much here, it is simply provided for reference. Consider the following Player class,
Player.java

package simple;

public class Player {

public String name;

    public Player(){
    }

    public String toString(){
        return name;
    }
}

Following is the example Client that makes use of the Player class. Note that we haven’t passed anything of type Module to the Guice.createInjector() method simply because we don’t want anything to be get bound (interface to implementation) in the Application Code.
PlayerTest.java

package simple;

import com.google.inject.Guice;
import com.google.inject.Injector;

public class PlayerTest {

public static void main(String[] args) {

    Injector injector = Guice.createInjector();
    Player player = injector.getInstance(Player.class);
    player.name = "David Boon";
    System.out.println(player);
    }
}

6.3) Resolving Multiple Dependencies

In this section, let us see how to resolve multiple Dependencies by making use of @Inject Annotation. Let’s say that we have an Object which is directly referring two or more Objects. For this simplest case, let the scenario be, ‘A person owns a Laptop and a Mobile’.
Following is the code for both Mobile and Laptop classes.
Laptop.java

package multipledepenedencies;

public class Laptop {

    private String model;
    private String price;

    public Laptop(){
        this.model = "HP 323233232";
        this.price = "$545034";
    }

    public String toString(){
        return "[Laptop: " + model + "," + price + "]";
    }
}

Mobile.java

package multipledepenedencies;

public class Mobile {

private String number;

    public Mobile(){
        this.number = "988438434";
    }

    public String toString(){
        return "[Mobile: " + number + "]";
    }
}

Following is the code for the Person class which directly references Laptop and Mobile object. Note the use of @Inject Annotation used on the constructor.
Person.java

package multipledepenedencies;

import com.google.inject.Inject;

public class Person {

    private Mobile mobile;
    private Laptop laptop;

    @Inject
    public Person(Mobile mobile, Laptop laptop){
        this.mobile = mobile;
        this.laptop = laptop;
    }

    public void diplayInfo(){
        System.out.println("Mobile:" + mobile);
        System.out.println("Laptop:" + laptop);
    }
}

Following is the Client Code that makes use of this sample. Since we don’t have anything to do with Bindings, we didn’t pass any Module object in the Guice.createInjector() method.
MultipleDependencyTest.java

package multipledepenedencies;

import com.google.inject.Guice;
import com.google.inject.Injector;

public class MultipleDependencyTest {

    public static void main(String[] args) {

        Injector injector = Guice.createInjector();
        Person person = injector.getInstance(Person.class);
        person.diplayInfo();
    }
}

The above program will output something like the following,

Mobile:[Mobile: 988438434]
Laptop:[Laptop: HP 323233232,$545034]

6.4) Making use of Binding Annotation

In Guice, it is not possible to binding a type to more than one implementations. For example, the following code would result in a Runtime Error.

binderObject.bind(SomeType.class).to(ImplemenationOne.class);
binderObject.bind(SomeType.class).to(ImplemenationTwo.class);

The following would be consider as an Error in Guice as the SomeType is bounded to more than one implementation classes. This is an Error simply because Guice don’t know which Instance to be returned upon Client’s Request. But in language like Java, it is perfectly legal to have multiple implementations for some type T with the concept of interfaces. One way to achieve this way in Guice is to depend on Binding Annotations. For example, consider the Player interface,
Player.java

package playerservice;

public interface Player {

    public void bat();
    public void bowl();

}

Following are the implementations for the Player interface, GoodPlayer and BadPlayer.
GoodPlayer.java

package playerservice;

public class GoodPlayer implements Player{

    public void bat() {
        System.out.println("I can hit any ball");
    }

    public void bowl() {
        System.out.println("I can also bowl");
    }
}

BadPlayer.java

package playerservice;

public class BadPlayer implements Player{

    public void bat() {
        System.out.println("I think i can face the ball");
    }

    public void bowl() {
        System.out.println("I dont know bowling");
    }

}

Now we want to instruct to Guice that for the Player interface, we have multiple implementations in the form of GoodPlayer and BadPlayer. Anyway, finally the Client makes use of one of the concrete Implementations only. Either they will use an implementation of type Good Player or Bad Player. Through some Annotation mechanisms we are now going to instruct Guice about the multiple Implementations. Following is the code for that,
PlayerModule.java

package playerservice;

import com.google.inject.*;

public class PlayerModule implements Module{

    public void configure(Binder binder) {

        binder.bind(Player.class).annotatedWith(Good.class).to(
            GoodPlayer.class);
        binder.bind(Player.class).annotatedWith(Bad.class).to(
            BadPlayer.class);
    }
}

We have used two custom Annotation types Good and Bad. The above code essentially tells to bind the implementation to GoodPlayer if it is annotated with Good and bind the Player type to BadPlayer if it is annotated with Bad. Following is definition for both the Good and the Bad annotations.
Good.java

package playerservice;

import java.lang.annotation.*;
import com.google.inject.BindingAnnotation;

@Retention(RetentionPolicy.RUNTIME)
@BindingAnnotation
@Target(ElementType. LOCAL_VARIABLE)
public @interface Good {}

Bad.java

package playerservice;

import java.lang.annotation.*;
import com.google.inject.BindingAnnotation;

@Retention(RetentionPolicy.RUNTIME)
@BindingAnnotation
@Target(ElementType. LOCAL_VARIABLE)
public @interface Bad {}

Following is the Client code for the above Program. Note that when requesting for a particular implementation the Client directly specifies the Annotation on the local reference thereby making the Guice to identify the implementation class. The code @Good Player player essentially tells Guice that a concrete implementation of type GoodPlayer has to be injected into the player reference because that is how we have configured in the Player Module.
PlayerClient.java

package playerservice;

import com.google.inject.Guice;
import com.google.inject.Injector;
import com.google.inject.Module;

public class PlayerClient {

    public static void main(String[] args) {

        PlayerModule module = new PlayerModule();
        Injector injector = Guice.createInjector(new Module[]{module});

        @Good Player player = (Player)injector.getInstance(Player.class);
        player.bat();
        player.bowl();
    }
}

6.5) Named Annotations

Creating new Annotation types for every concrete implementation doesn’t provide to be much useful as the sole purpose of having such an Annotation is just to mark the Implementation class instance needed by the Clients. For that we have @Named annotation which can be used to name entities. And there is an utility method called Names.named() which when given a name returns the Named Annotation. For example, in the above Player Module can be replaced with something similar to the following,
PlayerModule.java

package playerservice;

import com.google.inject.Binder;
import com.google.inject.Module;

public class PlayerModule implements Module{

    public void configure(Binder binder) {

        binder.bind(Player.class).annotatedWith(Names.named("Good")).to(
            GoodPlayer.class);
        binder.bind(Player.class).annotatedWith(Names.named("Bad")).to(
        BadPlayer.class);
    }

}

Names.named("SomeName") will simply return an Annotation of type @Named encapsulated with the given name. Now, back in the Client code, we should use the @Named annotation along with the name. For example,

@Named("Good") Player goodPlayer = (Player)injector.getInstance(Player.class);

@Named("Bad") Player badPlayer = (Player)injector.getInstance(Player.class);

6.6) Writing a Simple Provider

Providers are Guice simply acts as Factories in creating and returning Objects. In most of the cases, Clients can directly depend on the Guice Framework for creating Objects for the Services that they are referring. Rarely, the Application code wants to customize the Object creation process for a particular type so as to control the number of objects created, to provide cache mechanism and so on. For that we have to depend on Guice Provider classes.
For example, let us say that we want to create the Object creation and maintenance process for MockConnection class which is given below.
MockConnection.java

package named;

public class MockConnection {

    public void connect(){
        System.out.println("Connecting to the mock database");
    }

    public void disConnect(){
        System.out.println("Dis-connecting from the mock database");
    }

}

Now let us write a simple Provider class that conforms to Guice Provider that creates and return MockConnection objects. Following is the code for the same.
ConnectionProvider.java

package named;

import com.google.inject.Provider;

public class ConnectionProvider implements Provider{

    @Override
    public MockConnection get() {

        // Do some customization mechanism here.
        MockConnection connection = new MockConnection();
        // Do some customization mechanism here too.
        return connection;
    }
}

Note that all custom Provider class must implement the Provider Interface and should override the get() method to return the objects created in some custom fashion. Now, the module should be aware of the Custom Provider class that so Guice can request the ConnectionProvider to create instances instead of creating them on its own. Following is the Module code along with the Client code.
ConnectionTest.java

package named;

import com.google.inject.*;

public class ConnectionTest {

    public static void main(String args[]){
        Injector injector = Guice.createInjector(
            new Module(){
                @Override
                public void configure(Binder binder) {
                    binder.bind(MockConnection.class).toProvider(
                        ConnectionProvider.class);
                }
            }
        );

        MockConnection connection =
        injector.getInstance(MockConnection.class);
        connection.connect();
        connection.disConnect();
    }
}

Note that in the Module.configure() method, we have bound the type MockConnection.class to a Provider by calling the method Binder.toProvider().

6) Conclusion

This article started off with the need to have a Dependency Injection Framework like Guice. Though there are so many Dependency Injection Frameworks coming these days, usage of Guice is simple and the API is also small. There is no need to maintain a separate XML file as all the Configuration related information is nicely encapsulated by means of Module mechanism. In this article the Core API along with the Guice Annotations was explored followed with plenty of Samples.

Comments

comments

About Krishna Srinivasan

He is Founder and Chief Editor of JavaBeat. He has more than 8+ years of experience on developing Web applications. He writes about Spring, DOJO, JSF, Hibernate and many other emerging technologies in this blog.

Comments

  1. Andrea says:

    Hi, Eclipse is telling me “Annotation @Named is disallowed for this location” when I have to substitute the @Good Player player annotation with the @Named(“Good”) Player goodPlayer.
    How should I work out this issue?

  2. David Kotlirevsky says:

    I Have the same Issue , Andrea… Can Anyone tell what’s Happend ?

    • Instead of using @Good annotation, I got the following to work:
      Player goodplayer = (Player)injector.getInstance(Key.get(Player.class, Names.named(“Good”)));
      goodplayer.bat();
      goodplayer.bowl();

  3. This is good. Thanks for the article!

  4. in ConnectionProvider.java
    public class ConnectionProvider implements Provider{
    should be :

    public class ConnectionProvider implements Provider{

Speak Your Mind

*