Two commands for the price of one

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:

abstract class LoginCommandModule {
  abstract Command loginCommand(LoginCommand command);
abstract class HelloWorldModule {
  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;

  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.

      modules = {
  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.


  • @IntoMap allows for the creation of a map with values of a specific type, with keys set using special annotations such as @StringKey or @IntKey. Because keys are set via annotation, Dagger ensures that multiple values are not mapped to the same key.
  • @IntoSet allows for the creation of a set of types to be collected together. It can be used together with @Binds and @Provides methods to provide a Set<ReturnType>.
  • @IntoMap and @IntoSet are both ways of introducing what is often called “multibindings”, where a collection contains elements from several different binding methods.

Previous · Next