Reputation: 2143
Say I want to create a general provider that returns the first item in a collection. Something like:
class P extends Provider<T> {
private final Provider<Collection<T>> provider;
FirstItemProvider(Provider<Collection<T>> provider) {
this.provider = provider;
}
@Override
public T get() {
Collection<T> input = provider.get();
Iterator<T> iter = input.iterator();
return iter.hasNext() ? iter.next() : null;
}
}
Now I have various such collections with different annotations and I want to add bindings to this provider, BUT, I also want to be able to traverse bindings with using DefaultBindingTargetVisitor and getDependencies().
I've tried something like:
bind(Key.get(type, annotation))
.toProvider(new P(
getProvider(
Key.get(Types.collectionOf(type.getType()), annotation)
)
));
This works fine in terms of binding, but the traversal doesn't wok as Guice doesn't detect the dependency.
I couldn't figure out any other way to bind to an annotated producer since it doesn't have an annotation on it.
Is there any way to do what I'm trying to do?
Thanks Yaron
Upvotes: 0
Views: 1713
Reputation: 12922
This works for me:
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import javax.inject.Provider;
import com.google.inject.AbstractModule;
import com.google.inject.Binder;
import com.google.inject.Guice;
import com.google.inject.Injector;
import com.google.inject.Key;
import com.google.inject.name.Names;
import com.google.inject.spi.Dependency;
import com.google.inject.spi.ProviderInstanceBinding;
import com.google.inject.spi.ProviderWithDependencies;
class FirstItemProvider<T> implements ProviderWithDependencies<T> {
private final Provider<? extends Collection<? extends T>> collectionProvider;
private final Key<? extends Collection<? extends T>> key;
public FirstItemProvider(Binder binder, Key<? extends Collection<? extends T>> key) {
this.collectionProvider = binder.getProvider(key);
this.key = key;
}
@Override
public T get() {
return collectionProvider.get().iterator().next();
}
@Override
public Set<Dependency<?>> getDependencies() {
return Collections.<Dependency<?>>singleton(Dependency.get(key));
}
}
class FooModule extends AbstractModule {
@Override
protected void configure() {
Key<List<String>> listKey = new Key<List<String>>(Names.named("foo")){};
Key<String> stringKey = new Key<String>(Names.named("foo")){};
bind(listKey).toInstance(Arrays.asList("foo", "bar"));
bind(stringKey).toProvider(new FirstItemProvider<>(binder(), listKey));
}
}
public class Foo {
public static void main(String[] args) {
Injector injector = Guice.createInjector(new FooModule());
Key<String> stringKey = new Key<String>(Names.named("foo")){};
ProviderInstanceBinding<String> binding = (ProviderInstanceBinding<String>)injector.getBinding(stringKey);
System.out.println(binding.getDependencies());
}
}
The output is
[Key[type=java.util.List<java.lang.String>, [email protected](value=foo)]]
Upvotes: 2