2

私はいくつかのクラスを実装しており、必要に応じてそれらをバインドするために注釈付きinterface Provider<Communication>の Guice を使用しています。@Named

@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 によって管理されます。Fooorを正しくバインドすると、追加作業なしでorProvider<Foo>を要求できるはずです。したがって、おそらくこれは必要ありません。FooProvider<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())));
}

Call消去のため、C 型のクラス リテラルを取得する方法は他にないため、モックまたは動的プロキシを使用すると失敗することにも注意してください。

SomeOtherInterface<Call>の代わりにバインドしたい場合はProvider<Call>、まだそうすることができますが、Guice のTypesutil クラスを使用して ParameterizedType を動的に作成し、それを への入力として使用する必要がありますKey#get(Type, Annotation)ParameterizedType実装の作成に関するもう少し詳しいコンテキストについては、この SO answerを読んでください。

于 2013-09-24T20:35:01.173 に答える
0

ありえないと思います。自分でファクトリを作成し、コードをインターフェイスの使用からファクトリの使用に変更できます。または、インターフェイスをプロバイダーにバインドすることもできます (ただし、これにより、コードが減ることなく増えます)。

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

(または、YOUR Provider は Guice-Provider ですか?)

于 2013-09-23T21:17:28.227 に答える