Two use cases - two names?
Today I did something I've never done before - I created a method that's an 'alias' to another method. I still think this is the right thing to do, but I still find it kind of weird...Getting Providers
Binder.getProvider()
allows your module to get a Provider<T>
while the injector is still being created. The returned provider can't be used until the injector is ready, but that usually isn't a deal breaker:public class ListOfFiltersModule extends AbstractModule {
public void configure() {
/* get the filters set, perhaps bound with multibindings */
final Provider<Set<Filter>> filterSetProvider
= getProvider(new TypeLiteral<List<Filter>>(){});
/* use that provider in a provider instance binding */
bind(new TypeLiteral<List<Filter>>() {}).toProvider(
new Provider<List<Filter>>() {
public List<Filter> get() {
Set<Filter> filtersUnordered = filterSetProvider.get();
List<Filter> result = new ArrayList<Filter>();
result.addAll(filtersUnordered);
Collections.sort(filteresUnordered, FILTER_ORDER);
return Collections.unmodifiableList(result);
});
}
}
For this purpose, this works pretty good.
Listing Dependencies
There's another use case for
getProvider
- making dependencies explicit. It's handy to include the list of bindings that a module wants right in the module. This helps Guice to fail-faster if a required binding is missing. More importantly, it makes the dependency obvious to the maintainers of the code:public class DeLoreanModule extends Module {
public void configure() {
/* bindings needed from other modules */
getProvider(FluxCapacitor.class);
getProvider(TimeCircuits.class);
/* our bindings */
bind(Car.class).toProvider(DmcCarProvider.class);
}
This is okay, but a clarifying comment is necessary here. Otherwise the
getProvider
call looks out of place - the maintainers you're trying to help may delete this "unnecessary" call!requireBinding
Giving
getProvider
a better name for use case #2 makes the intentions more explicit. It also means we can axe the now-redundant comment:public class DeLoreanModule extends Module {
public void configure() {
requireBinding(FluxCapacitor.class);
requireBinding(TimeCircuits.class);
bind(Car.class).toProvider(DmcCarProvider.class);
}
Behind-the-scenes, all
requireBinding()
does is call through to getProvider()
to ensure that key is bound. But this is just an implementation detail - we could later change requireBinding
to do something different if there was a preferred alternative.Multiple Names
We have two use cases and two names. But only one implementation! I think it's legit, but it's a bit surprising. Where else does this come up?