我有几个实现interface Provider<Communication>
的类,我正在使用带有@Named
注释的Guice来根据需要绑定它们,例如:
@Singleton
public class Verizon implements Provider<Call> {
...
}
@Singleton
public class TMobile implements Provider<Call> {
...
}
bind (new TypeLiteral<Provider<Call>>() {}).annotatedWith(
Names.named("Verizon")).to(Verizon.class);
bind (new TypeLiteral<Provider<Call>>() {}).annotatedWith(
Names.named("TMobile")).to(TMobile.class);
是否有一种干净的方法来实现将名称作为参数的工厂,例如:
public static <C extends Communication> Provider<C> getCallProvider(C communication) {
String providerName = communication.getProviderName();
return [Guice's matching object for type Provider<?> and @Named = providerName];
}
我尝试使用Injector,但Guice不会将通用参数作为TypeLiteral:
public <C extends Communication> Provider<C> getCommunicationProvider(C communication) {
return injector.getInstance(Key.get(new TypeLiteral<CommunicationProvider<C>>() {},
Names.named(communication.getProvider().getId())));
}
这引发:
com.google.inject.ConfigurationException: Guice configuration errors:
1) Provider<C> cannot be used as a key; It is not fully specified.
答案 0 :(得分:3)
提供商由Guice管理;当您正确绑定Foo
或Provider<Foo>
时,您应该可以申请Foo
或Provider<Foo>
而无需任何其他工作。因此,您可能不希望这样:
bind (new TypeLiteral<Provider<Call>>() {}).annotatedWith(
Names.named("Verizon")).to(Verizon.class);
相反,你可能想要这个:
bind(Call.class).annotatedWith(Names.named("Verizon")).toProvider(Verizon.class);
...这会让你注入@Named("Verizon") Provider<Call>
,但也会注入@Named("Verizon") call
。此时您的原始请求就像这样简单:
/**
* Because of erasure, at compile time the injector can only guarantee that it
* returns something that extends Communication, not necessarily C. The cast and
* @SuppressWarnings will help with that.
*/
@SuppressWarnings("unchecked")
public static <C extends Communication> Provider<C> getCommunicationProvider(
C communication) {
return (Provider<C>) injector.getProvider(Key.get(communication.getClass(),
Names.named(communication.toString())));
}
另请注意,由于擦除,没有其他方法可以获得类型C的类文字,因此使用Call
的模拟或动态代理将失败。
如果您想绑定SomeOtherInterface<Call>
而不是Provider<Call>
,您仍然可以这样做,但是您需要使用Guice的Types
util class动态创建ParameterizedType并将其用作输入Key#get(Type, Annotation)
。有关创建ParameterizedType实施的更多背景信息,请阅读this SO answer。
答案 1 :(得分:0)
我认为这是不可能的。您可以自己编写工厂并将代码从使用界面更改为使用工厂。或者你可以将你的接口绑定到一个Provder(但这会导致更多的代码不会更少)。
bind (new TypeLiteral<Provider<Call>>() {}).annotatedWith(
Names.named("Verizon")).toProvider(new Provider<Provider<Call>>(){public Provider get(){return new Verizon();}});
(或者您的提供者是Guice-Provider吗?)