So far, CommandRouter only supports a single command at a time, but we’d like
to have it support many commands.
You’ll notice that if you try to add both modules together
(@Component(modules = {HelloWorldModule.class, LoginCommandModule.class})),
Dagger will report an error. The two modules conflict—they each tell Dagger how
to create a single Command, and Dagger doesn’t know which should win.
We want CommandRouter to depend on multiple commands instead of just one.
Since our CommandRouter wants a map of commands, we’ll use @IntoMap to map
each Command our application uses to the prefix of the command:
@Module
abstract class LoginCommandModule {
@Binds
@IntoMap
@StringKey("login")
abstract Command loginCommand(LoginCommand command);
}
@Module
abstract class HelloWorldModule {
@Binds
@IntoMap
@StringKey("hello")
abstract Command helloWorldCommand(HelloWorldCommand command);
}
The @StringKey annotation, combined with @IntoMap, tells Dagger how to
populate a Map<String, Command>. Note that our Command interface no longer
needs a key() method because we’re telling Dagger what the key is directly.
To take advantage of this, we can switch CommandRouter’s constructor parameter
to Map<String, Command>. Notice that Command on its own won’t work anymore.
final class CommandRouter {
private final Map<String, Command> commands;
@Inject
CommandRouter(Map<String, Command> commands) {
// This map contains:
// "hello" -> HelloWorldCommand
// "login" -> LoginCommand
this.commands = commands;
}
...
}
Now we can add both HelloWorldModule and LoginCommandModule
in the @Component annotation of CommandRouterFactory.
@Component(
modules = {
HelloWorldModule.class,
LoginCommandModule.class,
SystemOutModule.class
})
interface CommandRouterFactory {
CommandRouter router();
}
If you run the application now, you’ll see that both hello and login <your
name> both work. Make sure to update the @Component annotation to include
both modules.
CONCEPTS
@IntoMapallows for the creation of a map with values of a specific type, with keys set using special annotations such as@StringKeyor@IntKey. Because keys are set via annotation, Dagger ensures that multiple values are not mapped to the same key.@IntoSetallows for the creation of a set of types to be collected together. It can be used together with@Bindsand@Providesmethods to provide aSet<ReturnType>.@IntoMapand@IntoSetare both ways of introducing what is often called “multibindings”, where a collection contains elements from several different binding methods.