问题
I am trying to implement a common provider for all the subclasses, imagine some schema:
SuperComponent.class
is the parent of ComponentA.class
and ComponentB.class
.
I have the provider:
@Provides
<T extends SuperComponent> List<T> providesComponents(Provider<T> provider) {
List<T> componentList = new ArrayList<>();
for (int i = 0; i < 5; i++) {
componentList.add(provider.get());
}
return componentList;
}
The idea is to call this provider when is required the objects List<ComponentA>
and/or List<ComponentB>
in another class' constructor.
Imagine something like:
public class ResourceManager {
List<ComponentA> componentAList;
List<ComponentB> componentBList;
@Inject
public ResourceManager(List<ComponentA> componentAList, List<ComponentB> componentBList) {
this.componentAList = componentAList;
this.componentBList = componentBList;
}
I get an error saying:
1) com.google.inject.Provider<T> cannot be used as a key; It is not fully specified.
How can I make it work? I know I can do it creating different providers for each of the List<ComponentA>
and List <ComponentB>
but I need it as in the reality the number of components is much larger than 2...
回答1:
I don't think there's a good built-in way to handle this--Guice can bind a lot, or inspect and manipulate its bindings, but does not have good interfaces to create meta-level bindings. You do have a few options, though:
Leave the List-constructing to the consumer, through Providers:
public static <T> List<T> createList(Provider<T> provider) { List<T> list = new ArrayList<T>(); for (int i = 0; i < 5; i++) { list.add(provider.get()); } return list; } @Inject MyConsumer(Provider<Foo> depProvider) { List<Foo> myFoos = createList(depProvider); }
List out the classes you need to bind like that and create the Providers in your
configure
method:public class MyModule extends AbstractModule { public void configure() { List<Class<?>> classList = Lists.newArrayList(Class1.class, Class2.class); for (Class<?> clazz : classList) { bind(listOf(clazz)).toProvider(new ComponentListProvider<?>(getProvider(clazz))); } } private static <T> Key<List<T>> listOf(Class<T> clazz) { return new Key<List<T>>() {}; } private static class ComponentListProvider<T> implements Provider<List<T>>() { private final Provider<T> wrappedProvider; ComponentListProvider(Provider<T> wrappedProvider) { this.wrappedProvider = wrappedProvider; } @Override public List<T> get() { return createList(wrappedProvider); } } }
This uses getProvider, an extremely handy method that retrieves a typed
Provider
that will work as soon as theInjector
is created (but not before).Write a module that does one of the above by iterating across every binding in the Module using Guice SPI.
Hope that helps!
来源:https://stackoverflow.com/questions/14403119/have-a-common-provider-for-subclasses-using-guice