web-dev-qa-db-ja.com

Guiceでジェネリックを注入する

いくつかの工場をGuiceに置き換えて、小さなプロジェクトを移行しようとしています(これは私の最初のGuiceトライアルです)。しかし、ジェネリックを注入しようとすると行き詰まります。 2つのクラスと1つのモジュールを使用して小さなおもちゃの例を抽出することができました。

import com.google.inject.Inject;

public class Console<T> {
  private final StringOutput<T> out;
  @Inject
  public Console(StringOutput<T> out) {
    this.out = out;
  }
  public void print(T t) {
    System.out.println(out.converter(t));
  }
}

public class StringOutput<T> {
  public String converter(T t) {
    return t.toString();
  }
}

import com.google.inject.AbstractModule;
import com.google.inject.Guice;
import com.google.inject.Injector;
import com.google.inject.TypeLiteral;


public class MyModule extends AbstractModule {

  @Override
  protected void configure() {
    bind(StringOutput.class);
    bind(Console.class);
  }

  public static void main(String[] args) {
    Injector injector = Guice.createInjector( new MyModule() );
    StringOutput<Integer> out = injector.getInstance(StringOutput.class);
    System.out.println( out.converter(12) );
    Console<Double> cons = injector.getInstance(Console.class);
    cons.print(123.0);
  }

}

この例を実行すると、次のことがわかります。

スレッド「メイン」の例外com.google.inject.CreationException:Guice作成エラー:

1) playground.StringOutput<T> cannot be used as a key; It is not fully specified.
  at playground.MyModule.configure(MyModule.Java:15)

1 error
    at com.google.inject.internal.Errors.throwCreationExceptionIfErrorsExist(Errors.Java:354)
    at com.google.inject.InjectorBuilder.initializeStatically(InjectorBuilder.Java:152)
    at com.google.inject.InjectorBuilder.build(InjectorBuilder.Java:105)
    at com.google.inject.Guice.createInjector(Guice.Java:92)

エラーメッセージを探してみましたが、役立つヒントは見つかりませんでした。さらにGuiceについてFAQジェネリックスを注入する方法についての質問に出くわしました。configureメソッドに次のバインディングを追加しようとしました。

bind(new TypeLiteral<StringOutput<Double>>() {}).toInstance(new StringOutput<Double>());

しかし、成功しませんでした(同じエラーメッセージ)。

誰かが私にエラーメッセージを説明し、私にいくつかのヒントを提供できますか?ありがとう。

28
paradigmatic

あなたが見ている特定の問題はおそらくbind(Console.class)ステートメントが原因だと思います。 TypeLiteralも使用する必要があります。または、どちらもバインドせず、ここに含まれるタイプは両方とも具象クラスであるため、JITバインディングが自動的に処理します。

さらに、次のコマンドでConsoleを取得する必要があります。

Console<Double> cons = 
   injector.getInstance(Key.get(new TypeLiteral<Console<Double>>(){}));

編集:TypeLiteralを使用しているという理由だけで、インスタンスにバインドする必要はありません。あなたはただすることができます:

bind(new TypeLiteral<Console<Double>>(){});

もちろん、上で述べたように、この場合はスキップして、Consoleに基づいてKeyを使用してインジェクターからTypeLiteralを取得すると、バインディングは暗黙的になります。 。

28
ColinD