Guice : Inject an ArrayList of Strings

狂风中的少年 提交于 2019-12-06 01:49:01

I think you are misunderstanding how modules are supposed to work.

Modules don't create the objects, modules define rules for how objects might be created when they are needed.

The reason MapBinder would help is that you would define all of the services in your radio buttons list, and then use the injected map to activate the services that you need.

Here's some code to illustrate what I mean:

public class ServiceModule extends AbstractModule {
  protected void configure() {
    MapBinder<String, Service> mapbinder
        = MapBinder.newMapBinder(binder(), String.class, Service.class);
    mapbinder.addBinding("service1").to(Service1.class).in(Singleton.class);
    mapbinder.addBinding("service2").to(Service2.class);
    // Define ALL the services here, not just the ones being used.
    // You could also look this up from a ClassLoader or read from a configuration file if you want
  }
}

Then, inject the MapBinder to your ServiceManager class - which is not a module:

public class ServiceManager {
  private final Map<String, Service> serviceMap;

  @Inject
  public ServiceManager(Map<String, Service) serviceMap) {
    this.serviceMap = serviceMap;
  }

  // This is just one way to do it. It depends on how your UI works
  public void startAll(List<String> serviceList) {
    for(String serviceName : serviceList) {
      serviceMap.get(serviceName).start();
    }
  }
}

This is easy to do Guice:

bind(new TypeLiteral<List<String>>() {})
    .annotatedWith(Names.named(Constants.REQ_SERVICES))
    .toInstance(requestedServices);

Note that in order to bind a List<String> without Java erasing the generics, you create a short-lived anonymous inner type (a subclass of TypeLiteral with empty body {}). You also use toInstance.

There's nothing wrong with having a module take parameters that are used for binding, and I prefer to do so over Multibindings when all of the bindings are easily collected in one place.

Take care to note that the ArrayList<String> you accept is mutable, so if you inject this in more than one place, one consumer could change the list permanently for everyone else. It may make more sense to use Guava's ImmutableList.copyOf(list) or Collections.unmodifiableList(list) (though the latter would still let the list change if the Module creator changes the passed-in list later).


Regarding your proposed application lifecycle, remember that Guice's bindings should stay more-or-less constant after injector creation. The lifecycle you describe could make sense a couple of ways:

  • Show your dialog without Guice's help, then create an Injector with the selected options
  • Inject your List<String> of all options, show the dialog, and then pass around the list
  • Inject your List<String> with all options, show the dialog, and then create a child injector containing your list of selected options

All of those, however, are feasible depending on how accessible you want the full list and selected list to be in your application.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!