Frequently Asked Questions
コンフィギュレーションパラメータはどのように注入すればよいのですか?
あなた自身のパラメータであることを識別させるためのバインディングアノテーションが必要です。 パラメータを定義するアノテーションを作成します。
/** * Annotates the URL of the foo server. */ @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.FIELD, ElementType.PARAMETER}) @BindingAnnotation public @interface FooServerAddress {}
このアノテーションをモジュール内で値にバインドします。
public class FooModule { private final String fooServerAddress; /** * @param fooServerAddress fooサーバのURL */ public FooModule(String fooServerAddress) { this.fooServerAddress = fooServerAddress; } @Override public void configure() { bindConstant().annotatedWith(FooServerAddress.class).to(fooServerAddress); ... } }
最後にクラスに注入します。
public class FooClient { @Inject FooClient(@FooServerAddress String fooServerAddress) { ... }
ビルトインの@Namedバインディングアノテーションを使うと、少々キーストロークを減らすことができるかもしれません。
コンフィギュレーションプロパティはどのようにロードすればよいのですか?
コンフィギュレーションファイル内のそれぞれのプロパティについて、Names.bindProperties()を使ってバインディングを作成してください。
Guice経由で作成したオブジェクトにどのようにパラメータを渡せばいいのですか?
注入される値として直接的にパラメータを渡すことはできません。 ただし、Guiceを使ってファクトリを作成し、そのファクトリを呼び出してオブジェクトを作成することはできます。
public class Thing { // 注意:ここでは@Injectアノテーションは使わない private Thing(A a, B b) { ... } public static class Factory { @Inject public Factory(A a) { ... } public Thing make(B b) { ... } } } public class Example { @Inject public Example(Thing.Factory factory) { ... } }
AssistedInjectを使ってファクトリのボイラープレートコード(決まりきったコード)を削除することを考慮してください。
二つの同じような、しかし少しだけ違うオブジェクトツリーを作成するにはどうしたらいいですか?
これは一般にrobot legs問題といわれるものです。ロボットを生成するとして、左足はLeftFootを注入し、右足にはRightFootを注入したいとします。しかし、二つのコンテキスト内ではただ一つのLegクラスしか使えないものとします。
PrivateModulesというソリューションがあります。二つの分離したプライベートモジュールを使用します、一つは@Left、もう一つは@Rightです。 それぞれはアノテーションされていないFoot.classとLeg.classを用います。 そして、アノテーションされたLeg.classのみを公開します。
class LegModule extends PrivateModule { private final Class<? extends Annotation> annotation; LegModule(Class<? extends Annotation> annotation) { this.annotation = annotation; } @Override protected void configure() { bind(Leg.class).annotatedWith(annotation).to(Leg.class); expose(Leg.class).annotatedWith(annotation); bindFoot(); } abstract void bindFoot(); } public static void main(String[] args) { Injector injector = Guice.createInjector( new LegModule(Left.class) { @Override void bindFoot() { bind(Foot.class).toInstance(new Foot("leftie")); } }, new LegModule(Right.class) { @Override void bindFoot() { bind(Foot.class).toInstance(new Foot("righty")); } }); }
Alen Vreckoの完全な例を参照してください。
訳注:Robot Legs Problemを参照のこと。
内部クラスに注入する方法は?
Guiceではサポートしていませんが、ネストされたクラス(static inner class)に注入することはできます。
class Outer { static class Nested { ... } }
ジェネリック型を持つクラスに注入するには?
パラメトライズ型のクラスを注入したい場合があると思います。List<String>のような。
class Example { @Inject void setList(List<String> list) { ... } }
バインディングを作成するには、TypeLiteralを使う必要があります。TypeLiteralは完全なパラメトライズタイプを指定するための特別なクラスです。
@Override public void configure() { bind(new TypeLiteral<List<String>>() {}).toInstance(new ArrayList<String>()); }
オプショナルなパラメータをコンストラクタに注入するには?
コンストラクタも@Providesメソッドもオプショナルインジェクションをサポートしていません。 なんとかするには、オプショナルな値を保持する内部クラスを作成することです。
class Car { private final Engine engine; private final AirConditioner airConditioner; @Inject public Car(Engine engine, AirConditionerHolder airConditionerHolder) { this.engine = engine; this.airConditioner = airConditionerHolder.value; } static class AirConditionerHolder { @Inject(optional=true) AirConditioner value = new NoOpAirconditioner(); } }
これによって、デフォルト値を指定することもできます。
メソッドインターセプタに注入するには?
MethodInterceptorに注入するには、標準のbindInterceptor()呼び出しとともにrequstInjectionを使ってください。
public class NotOnWeekendsModule extends AbstractModule { protected void configure() { MethodInterceptor interceptor = new WeekendBlocker(); requestInjection(interceptor); bindInterceptor(any(), annotatedWith(NotOnWeekends.class), interceptor); } }
他の質問に答えてもらうには?
google-guiceディスカッショングループにポストしてください。