Внедрение родового factory в Guice
Следующий код представляет собой пример factory, который создает a Bar<T>
с учетом Foo<T>
. factory не заботится о том, что T
: для любого типа T
он может сделать Bar<T>
от Foo<T>
.
import com.google.inject.*;
import com.google.inject.assistedinject.*;
class Foo<T> {
public void flip(T x) { System.out.println("flip: " + x); }
}
interface Bar<T> {
void flipflop(T x);
}
class BarImpl<T> implements Bar<T> {
Foo<T> foo;
@Inject
BarImpl(Foo<T> foo) { this.foo = foo; }
public void flipflop(T x) { foo.flip(x); System.out.println("flop: " + x); }
}
interface BarFactory {
<T> Bar<T> create(Foo<T> f);
}
class Module extends AbstractModule {
public void configure() {
bind(BarFactory.class)
.toProvider(
FactoryProvider.newFactory( BarFactory.class, BarImpl.class )
);
}
}
public class GenericInject {
public static void main(String[] args) {
Injector injector = Guice.createInjector(new Module());
Foo<Integer> foo = new Foo<Integer>();
Bar<Integer> bar = injector.getInstance(BarFactory.class).create(foo);
bar.flipflop(0);
}
}
Когда я запускаю код, я получаю следующие ошибки от Guice:
1) No implementation for BarFactory was bound.
at Module.configure(GenericInject.java:38)
2) Bar<T> cannot be used as a key; It is not fully specified.
Единственная ссылка, которую я могу найти для дженериков в документации Guice, заключается в использовании TypeLiteral
. Но у меня нет буквального типа, у меня есть общий заполнитель, который вообще не относится к factory. Любые советы?
Ответы
Ответ 1
Один из вариантов состоит в том, чтобы просто написать шаблонную панель BarFactory вручную:
class BarImplFactory implements BarFactory {
public <T> Bar<T> create(Foo<T> f) {
return new BarImpl(f);
}
}
Связывание становится
bind(BarFactory.class).to(BarImplFactory.class);
Ответ 2
Если вы считаете, что в качестве системы проводки, подобной spring, то на самом деле не имеет смысла подключать общий экземпляр. Вы подключаете конкретные экземпляры к ключам, так что, когда другой экземпляр класса отмечает что-то с @Inject BarFactory, вы получаете конкретный созданный экземпляр.
Поскольку ваша реализация является общей, вы не предоставили достаточно информации для ввода конкретного экземпляра. Хотя я не использовал factoryprovider, я полагаю, что вам нужно привязать Barfactory к полностью параметризованному экземпляру, например. BarImpl<Concrete>
вместо BarImpl)
Кстати, так как вы привязываете BarFactory.class, если хотите связать несколько экземпляров, вам придется каким-то образом их поднять, либо по имени, что-то вроде (не проверили синтаксис, но)
bind(BarFactory.class).annotatedWith(Names.named("name1"))
.toProvider(
or by generics, bind(BarFactory<Concrete>).toProvider...