2014-04-02

Guice Tutorial - 03 - Providers

Introduction

Dependencies injected by Guice are generally created using annotated constructor. But sometimes you need a generator of specific class objects or you have to initialize your class before using it. These goals you can meet using providers. First, suppose you have ReportController, which stores given message with actual date in some place (database, file).


Injecting Provider

If you want to write good unit tests, you should protect yourself against changing date, so you can inject a kind of date generator - Provider of Date.
public class DateProviderTest {
    @Test
    public void shouldGetAnotherTimeForEachGet() throws InterruptedException {
        // given
        Injector injector = Guice.createInjector();
        Provider<Date> sut = injector.getProvider(Date.class);
        // when
        Date firstDate = sut.get();
        Thread.sleep(1);
        Date secondDate = sut.get();
        // then
        assertNotNull(firstDate);
        assertNotNull(secondDate);
        assertNotEquals(firstDate.getTime(), secondDate.getTime());
    }
}
In unit tests for classes, which use this provider you only need to mock Provider interface and return fixed date on each call.


Injecting via provider

Sometimes your objects should be additionally prepared before using, for example you have to call initialize method. It also could be done in described above way or you could use ProvidedBy annotation and explicit define Provider for your class. First, let's define class which should be initialized before using:
@ProvidedBy(ReportSessionFactory.class)
public class ReportSession {
    private boolean initialized;

    public ReportSession() {}

    public void init() {
        this.initialized = true;
    }

    public boolean isInitialized() {
        return initialized;
    }
    public boolean report(final String reportMessage, final Date date) {
        if(!initialized){
            return false;
        }
        // ...
        return true;
    }
}
ProvidesBy points to class which implements Provider interface:
public class ReportSessionFactory implements Provider<ReportSession> {
    @Override
    public ReportSession get() {
        ReportSession reportSession = new ReportSession();
        reportSession.init();
        return reportSession;
    }
}
Now when we will inject object of class ReportSession it will be given to us from provider and already initialized:
public class ReportSessionProviderTest {
    @Test
    public void shouldInitReportSession() {
        // given
        Injector injector = Guice.createInjector();
        ReportSession sut = injector.getInstance(ReportSession.class);
        // when
        boolean result = sut.isInitialized();
        // then
        assertTrue(result);
    }
}

Conclusion

When you need to inject a generator of runtime dependent objects or have to call method of dependency immediately after constructor, Guice providers are the best options for you. Sources are available here.

No comments:

Post a Comment