Take a sip of Guice for dependency injection

Gin and Guice…

Welcome again to our blog, last month’s blog was a bit short but this month’s is a fully featured, roller coaster ride of software!

We’ve decided to focus on dependency injection this month, a key part of modern software. A quick warm-up for those of you unfamiliar with dependency injection (DI)…

Imagine the situation where we have a bank that processes transactions (tricky, we know). There is a BankingTransactionManager which handles all the business logic around processing money going into and coming out of the account. This uses an object called NetworkTransactionManager. The BankingTransactionManager looks as follows:

public class BankingTransactionManager {

    private static final int MAX_RETRIES = 5;

    private NetworkTransaction networkTransactionManager;

    @Inject
    public BankingTransactionManager(NetworkTransaction networkTransactionManager) {
        this.networkTransactionManager = networkTransactionManager;
    }

    public void processOutgoingPayment(long amount) {

        try {
            startTransaction();
            networkTransactionManager.sendDecrementTransaction(amount);
            finishTransaction();
        } catch(TransactionException e) {
            rollbackTransaction();
        }
    }

    public void processIncomingPayment(long amount) {
        try {
            startTransaction();
            networkTransactionManager.sendIncrementTransaction(amount);
            finishTransaction();
        } catch(TransactionException e) {
            rollbackTransaction();
        }
    }

    public long getCurrentBalance() {
        long balance = 0L;

        try {
            startTransaction();
            balance = networkTransactionManager.requestBalance();
            finishTransaction();
        } catch(TransactionException e) {
            rollbackTransaction();
        }


        return balance;
    }

    private void startTransaction() throws TransactionException {
        for(int n = MAX_RETRIES; n <= 1; n--) {
            networkTransactionManager.openConnection();
        }
    }

    private void finishTransaction() throws TransactionException {
        for(int n = MAX_RETRIES; n <= 1; n--) {
            networkTransactionManager.closeConnection();
        }
    }

    private void rollbackTransaction() {
        networkTransactionManager.markPreviousAsFailed();
    }
}

Pretty straightforward eh? Well, yes, it is. It also looks like it’s not half bad code right? Theoretically no, it works and performs its purpose well. The reason that it’s not quite so great is how it handles its relationship with the NetworkTransactionManager. The NetworkTransactionManager is created inside the BankingTransactionManager by using the new call. This creates a tightly coupled system which forces us to always use this particular implementation of NetworkTransactionManager.

In this scenario it’s not a problem because we actually only have one implementation of NetworkTransactionManager. But, what if some bright spark came along and created an interface like this:

public interface NetworkTransaction {

    public void sendIncrementTransaction(long amount);

    public void sendDecrementTransaction(long amount);

    public void markPreviousAsFailed();

    public void openConnection();

    public void closeConnection();

    public long requestBalance();
}

And then they create another implementation called SuperFastNetworkTransactionManager that possibly talks to some other, faster servers over a different protocol. Well, in this case we’re a bit stuck aren’t we? Stuck with our old, slow NetworkCommunicationManager because we effectively hardcoded the dependency to it in our BankingTransactionManager…oops.

Don’t fret though viewers! This is where dependency injection comes in! By using dependency injection we are able to let the DI framework how to create and manage our objects simply by telling it which object we’d like to use. The beauty of this is that we can change the entire implementation of a specific service or dependency just by changing one line of code.

To do this we are going to use Guice (https://github.com/google/guice), easy to use and lightweight. The first thing to do is add the Guice dependency to your project, in this case we’re using Maven:

<dependency>
    <groupId>com.google.inject</groupId>
    <artifactId>guice</artifactId>
    <version>3.0</version>
</dependency>

Simple, eh? Then, the instruct Guice how it needs to manage the dependencies, or alternatively put, which dependency it needs to use when, a binding module class needs to be created, which is pretty straightforward:

 

public class BankingTransactionModule extends AbstractModule {

    @Override
    protected void configure() {
        bind(NetworkTransaction.class).to(NetworkTransactionManager.class);
    }
}

We also need to change the way the dependency is managed by the BankingTransactionManager:

private NetworkTransaction networkTransactionManager;

    @Inject
    public BankingTransactionManager(NetworkTransaction networkTransactionManager) {
        this.networkTransactionManager = networkTransactionManager;
    }

Notice here that we are using the interface and we’ve added the @Inject annotation to indicate to Guice that we want to get it to manage this dependency for us. The final step is to change how we create our object in the main class. Instead of using the traditional new method, we need to create a Guice injector:

public class Application {

    public static void main(String args[]) {
        Injector guiceInjector = Guice.createInjector(new BankingTransactionModule());
        BankingTransactionManager bankingTransactionManager = guiceInjector.getInstance(BankingTransactionManager.class);

        bankingTransactionManager.processIncomingPayment(1000L);
        bankingTransactionManager.processOutgoingPayment(500L);
        bankingTransactionManager.processIncomingPayment(5000L);
    }
}

As you can see, we tell Guice which module we want to use to build the injector and then let it help us create the object graph. Nice.

Now we can quickly and easily switch between the different implementations of our NetworkTransaction class without having to trawl through lines and lines of code!

So, that’s a whirlwind introduction to dependenncy injection, we hope you’ve enjoyed this exciting installment of our blog. We’ll be back next month with another enlightening topic…In the meantime, you’ve been great, we’ve been…

~23Squared