2008年6月19日木曜日

GuiceでDI: BindingAnnotation

先のGuiceでDI、のエントリ中で、NamedというAnnotaionを使った名称で実装を区別...の話を書いたが、Google Docで公開されている資料によるとGuiceではNamed Annotationは非推奨らすぃ。

文字列で名称を与えるのが気に喰わないらしい。まぁ確かにそうだ。せっかくJavaで全部やるんだから…というワケで、どのような方法が推奨されているかというと、名称を与えたBind専用のAnnotationを作る。先の例だと、「mysql」「postgresql」という文字列ではなく、いちいちその名称のAnnotationを作る。

"mysql"用のBindingAnnotation

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

import com.google.inject.BindingAnnotation;

@Retention(RetentionPolicy.RUNTIME)
@Target( { ElementType.FIELD, ElementType.PARAMETER, ElementType.METHOD })
@BindingAnnotation
public @interface MySql {}

"postgresql"用のBindingAnnotation

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

import com.google.inject.BindingAnnotation;

@Retention(RetentionPolicy.RUNTIME)
@Target( { ElementType.FIELD, ElementType.PARAMETER, ElementType.METHOD })
@BindingAnnotation
public @interface PostgreSql {}

BusinesLogicの@Injectを修飾する"mysql"はこんなカンジ

import com.google.inject.Inject;

public class BusinessLogic {
    @Inject
    @MySql
    private Converter converter;

    public void doBusiness(Table table) {
        String sql = converter.convert(table);
        System.out.println(sql);
    }
}

Guiceの設定をするAbstractModule#configure()はこんなカンジ

    // Guiceの設定
    Injector injector = Guice.createInjector(new AbstractModule() {
        @Override
        protected void configure() {
            bind(Converter.class).annotatedWith(MySql.class).to(MySQLConverter.class);
            bind(Converter.class).annotatedWith(PostgreSql.class).to(PostgreSQLConverter.class);
        }
    });

ご覧の通り、かなり面倒。だが実装の名称も文字列で与えるのではなく型で与える事によりタイプミスも少なくなり、実行前にIDE内でエラーとして検出されるのだ!…とはいえ、めっちゃ面倒。Namedでいいと思う。

コメントを投稿