Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Guice Binding for List of generic Objects

Tags:

java

guice

What is the binding statement I need to tell guice to that I want a OneFoo and a TwoFoo injected into Bar as a List of Foo? The setup here is a chain of responsibility. Right now I have two implementations, but Bar doesn't need to know that.

@Inject
Bar(List<Foo> foos) {...}
...
class OneFoo implements Foo {
    @Inject
    OneFoo(...) {...}
...
class TwoFoo implements Foo {
    @Inject
    TwoFoo(...) {...}

But I'm struggling with using the Types, TypeLiteral, etc to configure the binding where the two Foo implementations will given to Bar.

like image 645
James A Wilson Avatar asked Apr 18 '13 17:04

James A Wilson


1 Answers

If you know at compile time the bindings, you can use an @Provides method in your module:

class MyModule extends AbstractModule() {
    @Override
    protected void configure() {
        // ...
    }

    @Provides
    @Inject
    public List<Foo> foos(OneFoo one, TwoFoo two) {
        return Arrays.asList(one, two);
    }
}

You can expand foos's argument list as needed. A similar, but more verbose approach, would be to use a Provider:

protected void configure() {
    bind(new TypeLiteral<List<Foo>>() {})
       .toProvider(FooListProvider.class);
}

static class FooListProvider implements Provider<List<Foo>> {
    @Inject
    Provider<OneFoo> one;
    @Inject
    Provider<TwoFoo> two;

    public List<Foo> get() {
        return Arrays.asList(one.get(), two.get());
    }
}

In case you want a singleton list in which the OneFoo and TwoFoo are injected, you can add an @Singleton annotation. I would recommend also making the list immutable at that point:

@Singleton
@Provides
@Inject
public List<Foo> foos(OneFoo one, TwoFoo two) {
    return Collections.unmodifiableList(Arrays.asList(one, two));
}

If on the other hand, you want a singleton list for which OneFoo and TwoFoo are NOT injected, you can use a TypeLiteral:

@Override
protected void configure() {
    bind(new TypeLiteral<List<Foo>>() {})
        .toInstance(Arrays.asList(new OneFoo(), new TwoFoo()));
}

In this case too, again, I'd suggest making the list unmodifiable.

like image 198
ɲeuroburɳ Avatar answered Nov 03 '22 06:11

ɲeuroburɳ