Reputation: 254
I'm trying to support third party extensions using map multibindings, but I can't wrap my head around how it's supposed to provide an extensible infrastructure. It seems like it should be really simple, but the Dagger 2 documentation on multibindings doesn't actually provide an example of how to do it. I want other developers to be able to write their own implementations of an interface that I provide, and then have that seamlessly integrate.
Here's some sample code that shows what I'm attempting to do:
// This is the interface that third parties can implement.
public interface FooService {
public void run();
}
// This is the default implementation of the interface that I provide.
class DefaultFooImpl implements FooService {
DefaultFooImpl() { ... }
@Override public void run() { ... }
}
// Third parties would need to add their own modules to provide their
// implementations of FooService on different keys (right?).
@Module class DefaultImplModule {
@Provides(type = MAP)
@StringKey("default")
static FooService provideDefaultImpl() {
return new DefaultFooImpl();
}
}
// PROBLEM! This won't work for third-party implementations, since I
// can't include their modules here because I don't know them.
@Component(modules = DefaultImplModule.class)
interface FooServiceComponents {
Map<String, FooService> fooServices();
}
public class FooDispatcher {
// PROBLEM! How do I actually inject this map? Does this work?
@Inject Map<String, FooService> fooServices;
void callFooService(String whichService) {
// whichService is any of the Strings in the combined services map.
// For the default implementation, you'd pass in "default".
this.fooServices.get(whichService).run();
}
}
So what's the missing piece that ties this all together and actually makes it work? Thanks.
Upvotes: 0
Views: 659
Reputation: 2823
Here is the pattern I use - the Module will have to be configured at time of using the Component builder by passing your arguments. Strongly recommend sparing usage and only if needed - things should be as simple as you need them to be, but not any more :-)
@Module
class ConfigurableModule {
private IDependencyOne one;
private IDependencyTwo two;
...
ConfigurableModule() {
}
ConfigurableModule(IDependencyOne one, IDependencyTwo two, ...) {
this.one = one;
this.two = two;
}
@Provides IDependencyOne getIDependencyOne(MyIDependencyOneImpl impl) {
return one == null ? impl : one;
}
@Provides IDependencyTwo getIDependencyTwo(MyIDependencyTwoImpl impl) {
return one == null ? impl : one;
}
}
Upvotes: 1