Disambiguating Between Instances With Google Guice
Join the DZone community and get the full member experience.
Join For FreeGoogle guice provides a neat way to select a target implementation if there are multiple implementations of an interface. My samples are based on anexcellent article by Josh Long(@starbuxman) on a similar mechanism that Spring provides.
So, consider an interface called MarketPlace having two implementations, an AndroidMarketPlace and AppleMarketPlace:
interface MarketPlace { } class AppleMarketPlace implements MarketPlace { @Override public String toString() { return "apple"; } } class GoogleMarketPlace implements MarketPlace { @Override public String toString() { return "android"; } }
and consider a user of these implementations:
class MarketPlaceUser { private final MarketPlace marketPlace; public MarketPlaceUser(MarketPlace marketPlace) { System.out.println("MarketPlaceUser constructor called.."); this.marketPlace = marketPlace; } public String showMarketPlace() { return this.marketPlace.toString(); } }
A good way for MarketPlaceUser to disambiguate between these implementations is to use a guice feature called Binding Annotations. To make use of this feature, start by defining annotations for each of these implementations this way:
@Retention(RetentionPolicy.RUNTIME) @Target({ElementType.FIELD, ElementType.PARAMETER}) @BindingAnnotation @interface Android {} @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.FIELD, ElementType.PARAMETER}) @BindingAnnotation @interface Ios {}
and inform the Guice binder about these annotations and the appropriate implementation corresponding to the annotation:
class MultipleInstancesModule extends AbstractModule { @Override protected void configure() { bind(MarketPlace.class).annotatedWith(Ios.class).to(AppleMarketPlace.class).in(Scopes.SINGLETON); bind(MarketPlace.class).annotatedWith(Android.class).to(GoogleMarketPlace.class).in(Scopes.SINGLETON); bind(MarketPlaceUser.class).in(Scopes.SINGLETON); } }
Now, if MarketPlaceUser needs to use one or the other implementation, this is how the dependency can be injected in:
import com.google.inject.*; class MarketPlaceUser { private final MarketPlace marketPlace; @Inject public MarketPlaceUser(@Ios MarketPlace marketPlace) { this.marketPlace = marketPlace; } }
This is very intuitive. If you have concerns about defining so many annotations, another approach could be to use @Named built-in Google Guice annotation, this way:
class MultipleInstancesModule extends AbstractModule { @Override protected void configure() { bind(MarketPlace.class).annotatedWith(Names.named("ios")).to(AppleMarketPlace.class).in(Scopes.SINGLETON); bind(MarketPlace.class).annotatedWith(Names.named("android")).to(GoogleMarketPlace.class).in(Scopes.SINGLETON); bind(MarketPlaceUser.class).in(Scopes.SINGLETON); } }
and use it this way, where the dependency is required:
import com.google.inject.*; class MarketPlaceUser { private final MarketPlace marketPlace; @Inject public MarketPlaceUser(@Named("ios") MarketPlace marketPlace) { this.marketPlace = marketPlace; } }
Published at DZone with permission of Biju Kunjummen, DZone MVB. See the original article here.
Opinions expressed by DZone contributors are their own.
Comments