Bindings: 注入する物を定義する

ここで説明するのは Bindingsに関して三種類

  • Linked Bindings
  • Instance Bindings
  • Binding Annotation

Linked Bindings

Moduleの configureの中で bind(Interface.class).to(Concrete.class); とやる事で Interfaceへ注入するべき実装が Concrete.classである事を宣言する

public class GreetingModule extends AbstractModule {

  @Override
  protected void configure() {
    bind(SayHelloInterface.class).to(Konnitiwa.class);
    bind(SayGoodbyeInterface.class).to(Sayonara.class);
  }

}

Instance Bindings

toInstance()を使って Instanceを直接 Bind

@Inject @Named("URL")
String site_url;

bind(Sting.class).annotatedWith(Names.named("URL")).toInstance("https://www.google.com/");

あまり良い例じゃないか。

こうする事で Stringの Fieldが@Inject @Named(“URL”)とAnnotationされているときに、InjectorによってURL文字列が注入されます。

Injectorのインスタンス作成時間に影響するらしいので、インスタンス作成に時間のかかるオブジェクトをtoInstanceで注入するのは やめておけというのがドキュメントにかかれてます。

Binding Annotation

同じインターフェースに対して異なる 実装を Bindingしたい場合

public class Client {

    @Inject
    private Service normalService;

    @Inject
    private Service specialService;

    public Client() {
    }

}

annotatedWithで条件を付けてやる

public class Client {

    @Inject
    private Service normalService;

    @Inject @Named("Special")
    private Service specialService;

    public Client() {
    }
}

bindの仕方は以下のような形

// 特に条件無し
bind(Service.class).to(ServiceImpl.class);

// 条件付き
bind(Service.class).annotatedWith(Names.named("Special")).to(ServiceImplSpecial.class);

としてやれば、それぞれ Module側の指定にしたがって適切にInjectされる。

@Namedによる Bindingは文字列なので簡単に間違える。アノテーションを独自に実装する事でコンパイル時チェックが効くようになる。

以下は @Special というアノテーションの実装

import com.google.inject.BindingAnnotation;

import java.lang.annotation.Target;
import java.lang.annotation.Retention;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
import static java.lang.annotation.ElementType.PARAMETER;
import static java.lang.annotation.ElementType.FIELD;
import static java.lang.annotation.ElementType.METHOD;

@BindingAnnotation
@Target({ FIELD, PARAMETER, METHOD })
@Retention(RUNTIME)
public @interface Special {}

クライアント側

@Inject @Special
private Service specialService;

Module側

bind(Service.class).to(ServiceImpl.class);
bind(Service.class).annotatedWith(Special.class).to(ServiceImplSpecial.class);