@ImplementedBy VS TypeLiteral

Google guice のインジェクションバインド定義で、
com.google.inject.TypeLiteral は、良くこのように使用される。

Injector injector = Guice.createInjector(new AbstractModule(){
      @Override
      protected void configure(){
         binder().bind(new TypeLiteral<List<String>>(){})
         .toInstance(new ArrayList<String>());
      }
   }
);

(例題)

import java.util.function.Function;
import com.google.inject.ImplementedBy;

public interface SampleBuilder<R extends BaseDto>{
    public R create(String str, Function<String, R> function);
}
import java.util.function.Function;

public class SampleBuilderImpl<R extends BaseDto> implements SampleBuilder<R> {
    @Override
    public R create(String str, Function<String, R > function){
        return function.apply(str);
    }
}

インジェクション対象は、このような状況とする

@Inject private SampleBuilder<SampleDto> builder;

こんな時、TypeLiteral を使わずに、

Injector injector = Guice.createInjector(new AbstractModule(){
    @Override
    protected void configure(){
        binder().bind(SampleBuilder.class).to(SampleBuilderImpl.class);
    }
});

これはダメだ。
com.google.inject.ConfigurationException: Guice configuration errors
1) [Guice/MissingImplementation]: No implementation for SampleBuilder was bound.

と、怒られてしまう。

TypeLiteral を使うならこうする。

import com.google.inject.TypeLiteral;

Injector injector = Guice.createInjector(new AbstractModule(){
    @Override
    protected void configure(){
        binder().bind(new TypeLiteral<SampleBuilder<SampleDto>>(){}).to(new TypeLiteral<SampleBuilderImpl<SampleDto>>(){});
    }
});

これで解決なのだが、TypeLiteral の bind定義を書かなくても
インターフェースの方で、@ImplementedBy で実装クラスを指定する方法でも解決する。

import com.google.inject.ImplementedBy;

import java.util.function.Function;

@ImplementedBy(SampleBuilderImpl.class)
public interface SampleBuilder<R extends BaseDto>{
    public R create(String str, Function<String, R> function);
}

@ImplementedBy はとても便利