Guice

Links

Motivation

You want to do something, e.g. do the payment for a shop.

public boolean pay(Integer amount, String recipient) {
    // do payment
}

Maybe you need different variants of this. So having an interface and several implementations:

public interface PaymentInterface {
    public boolean pay(Integer amount, String recipient);
}
public class PaymentVisa implements PaymentInterface {
    @Override
    public boolean pay(Integer amount, String recipient) {
        System.out.println("Pay with Visa "+amount+" to recipient");
        return true;
    }
}

And a client, e.g. a shop code will use this like this

PaymentInterface payment=new PaymentVisa();
payment.pay(42, "John Doe");

The has some problems. If you want to replace the payment you have to search the full code for any place creating a payment, plus the code is hard to test without paying accidentally.

Standard solution would be to provide a factory for payments

public class PaymentFactory {
    public static PaymentInterface getPayment() {
        return new PaymentVisa();
    }
}

And the client uses it like this

PaymentInterface payment=PaymentFactory.getPayment();

Now you can switch die Payment implementation at one place, and the factory may return different implementations for tests as well.

Google Guice Dependency Injection

Different approach, Dependency Injection. The client gets its dependencies from the outside.

public class MyShop {
    private PaymentInterface payment;

    public MyShop(PaymentInterface pPayment) {
        payment=pPayment;
    }

    public void goShopping() {
        payment.pay(42, "John Doe");
    }
}

And the dependencies are provided when your client is created

MyShop shop=new MyShop(new PaymentVisa());

With Guice the is even more elegant. This is how to do Add this to your Maven project to get Guice

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

Now create a class which inherits from AbstractModule and in its configure method choose which implementation should be chosen every time the class PaymentInterface is required Google Guice LinkedBindings

import com.google.inject.AbstractModule;

public class PaymentModule extends AbstractModule {
    @Override
    protected void configure() {
        bind(PaymentInterface.class).to(PaymentVisa.class);
    }
}

In our client we add an annotation to the constructor that we need somebody to inject our dependencies

import com.google.inject.Inject;

public class MyShop {

    private PaymentInterface payment;

    @Inject
    public MyShop(PaymentInterface pPayment) {
        payment=pPayment;
    }
    public void goShopping() {
        payment.pay(42, "John Doe");
    }
}

In order to make Guice inject your dependencies for you, let Guice create your Client for you

Injector injector = Guice.createInjector(new PaymentModule());
MyShop shop = injector.getInstance(MyShop.class);
shop.goShopping();

Now if you want to do a unit test, add a mock Payment method

public class PaymentMock implements PaymentInterface {
    public boolean pay(Integer amount, String recipient) {
        System.out.println("We do NOT pay "+amount+" to recipient "+recipient+" as we are testing");
        return true;
    }
}

Within your unit tests (e.g. in the @Before method) get a special injector with a special Module class which binds the payment to the mock payment.

Injector testInjector = Guice.createInjector(new AbstractModule() {
    @Override
    protected void configure() {
      bind(PaymentInterface.class).to(PaymentMock.class);
    }
});

So the unit tests get their instances like this

MyShop shopTest = testInjector.getInstance(MyShop.class);
shopTest.goShopping();

Sometimes you want to be able to have more than one implementation of an interface available. You can either use self created annotations to mark with injection should be using which type

Google Guice BindingAnnotations

public class MyShop {

    @Inject
    public MyShop(
            @PayWithVisa       PaymentInterface pPayment1,
            @PayWithMastercard PaymentInterface pPayment2,
            @PayMock           PaymentInterface pPayment3) {
        payment1=pPayment1;
        payment2=pPayment2;
        payment3=pPayment3;
    }

and

import com.google.inject.AbstractModule;

public class PaymentModule extends AbstractModule {
    @Override
    protected void configure() {
        // bind(PaymentInterface.class).to(PaymentVisa.class);
bind(PaymentInterface.class).annotatedWith(PayWithVisa.class). to(PaymentVisa.class);
bind(PaymentInterface.class).annotatedWith(PayWithMastercard.class).to(PaymentMastercard.class);
bind(PaymentInterface.class).annotatedWith(PayMock.class). to(PaymentMock.class);
    }
}

Downside of this is that you have to create all required annotations with this code

import com.google.inject.BindingAnnotation;
import java.lang.annotation.Target;
import java.lang.annotation.Retention;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
import static java.lang.annotation.ElementType.PARAMETER;
import static java.lang.annotation.ElementType.FIELD;
import static java.lang.annotation.ElementType.METHOD;

@BindingAnnotation @Target({ FIELD, PARAMETER, METHOD }) @Retention(RUNTIME)
public @interface PayWithVisa {}

You can use the provided

@Named("PayWithVisa")

instead and bind with

bind(PaymentInterface.class).annotatedWith(Names.named("PayWithVisa")).to(PaymentVisa.class);

But you should prefer to create your own annotations.

Multibinding Imagine you have a method that accepts several payment implementations

@Inject
public PaymentCaller(Set<PaymentInterface> supportedPayments) {
}

And you want to bind some payment implementations to that. In your module class do this

final Multibinder<PaymentInterface> paymentbinder = Multibinder.newSetBinder(binder(), PaymentInterface.class);
paymentbinder.addBinding().to(PaymentVisa.class);
paymentbinder.addBinding().to(PaymentMasterCard.class);

Google Guice ProvidesMethods

If you want to control how the implementations are created (e.g. because you need to do something to them before they can be used), you can have @Provides methods in the Module class. The return type of the @Provides method decide which one to use

public class PaymentModule extends AbstractModule {

    @Override
    protected void configure() {
        //bind(PaymentInterface.class).to(PaymentVisa.class);
        bind(PaymentInterface.class).to(PaymentMastercard.class);
    }

    @Provides
    PaymentVisa providePaymentVisa() {
        PaymentVisa visa = new PaymentVisa();
        visa.setVisaCode(42);
        return visa;
    }

    @Provides
    PaymentMastercard providePaymentMastercard() {
        PaymentMastercard master = new PaymentMastercard();
        master.setMasterCardInit("abcd");
        return master;
    }
}

You can even manually control what type is returned. This method has the Provides annotation so when MyType needs to be injected that method will be called. The method itself gets two possible instances of MyType injected. Provider<Foo> makes that Injection lazy, so only if you try to get it, it is actually created. In the method you choose the instance you need.

@Provides
static MyType getMyType(@Named("mySwitch") final boolean mySwitch,
 final Provider<Bar> bar, final Provider<Foo> foo) {
  MyType result;
  if (mySwitch) {
    result=bar.get();
  } else {
    result=foo.get();
  }
  return result;
}

Google Guice ProviderBindings If creating the implementations gets more complex and you want to hide it somewhere, or if create them is expensive and you only want to do it if the implementation is really needed (lazy load) go for Provider. Create a special class which will create the implementation only once its get method is called

import com.google.inject.Provider;

public class VisaPaymentProvider implements Provider<PaymentInterface> {

    public PaymentInterface get() {
        PaymentVisa result = new PaymentVisa();
        result.setVisaCode(42);
        return result;
    }

}

In the module bind to the provider instead of the implemenation

//bind(PaymentInterface.class).to(PaymentVisa.class);
bind(PaymentInterface.class).toProvider(VisaPaymentProvider.class);
//bind(PaymentInterface.class).toProvider(VisaPaymentProvider.class).in(Singleton.class);

This will no longer create the implemenation, only the Provider

Injector injector = Guice.createInjector(new PaymentModule());

You can also bind from within a module fixed values to variables.

bindConstant().annotatedWith(DBUser.class)    .to("john");
bindConstant().annotatedWith(DBPassword.class).to("123456");

And within the class

@Inject @DBUser
private String dbUser;

@Inject @DBPassword
private String dbPassword;

Use Injector to inject named constant

injector.getInstance(Key.get(String.class, Names.named("annotation")));

Overwrite a Guice binding, useful for JUnit tests

Create a module that has the desired binding in its configure

public class TestOverwriteModule extends AbstractModule {
 @Override
 protected void configure() {
  bind(String.class).annotatedWith(Names.named("dbName")).toInstance("test-db");
 }
}

Add this module and maybe others to an array, e.g. overrideModules. Get the normal Guice modules and get the injector like this

Guice.createInjector(resolvedStage, Modules.override(normaleModules).with(overrideModules));

Inject depending on a constant

Usually you bind you implementation to and Interface via bind statements. You can also have an configuration constant (inject via @Named) and then inject something different, depending on its value. This is for example nice if one constant should change the injection of several different things

public class MyModule extends AbstractModule {

@Override
 protected void configure() {
  final MapBinder<String, MyInterface> map = MapBinder
    .newMapBinder(binder(), String.class, MyInterface.class);
  map.addBinding("foo").to(MyImplementation1.class);
  map.addBinding("bar").to(MyImplementation2.class);
 }

 @Provides
 public MyInterface selectMyInterface(final Map<String, MyInterface> map,
   @Named("your.fav.implementation") final String choose) {
  return map.get(choose);
 }
}