2

我有几个实现的类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.
4

2 回答 2

3

提供者由 Guice 管理;当您正确绑定 a FooorProvider<Foo>时,您应该能够要求 a FooorProvider<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>不是. 有关创建ParameterizedType实现的更多背景信息,请阅读此 SO answerProvider<Call>TypesKey#get(Type, Annotation)

于 2013-09-24T20:35:01.173 回答
0

我认为这是不可能的。您可以自己编写工厂并将代码从使用接口更改为使用工厂。或者你可以将你的接口绑定到一个 Provder(但这会导致更多的代码而不是更少)。

bind (new TypeLiteral<Provider<Call>>() {}).annotatedWith(
    Names.named("Verizon")).toProvider(new Provider<Provider<Call>>(){public Provider get(){return new Verizon();}});

(或者您的提供者是 Guice 提供者吗?)

于 2013-09-23T21:17:28.227 回答