バインド定義を蓄積の一歩

Custom Injection で紹介された、TypeListener をこんなふうにすれば
まとまってくる。
Module クラスをいろいろ書いて蓄積していく戦略が見えてくる。
(ただ、インナークラスにまとめただけだが、拡張性を
 隠蔽している点が良いのでは。。)

import java.lang.reflect.Field;
import org.apache.log4j.Logger;
import com.google.inject.AbstractModule;
import com.google.inject.MembersInjector;
import com.google.inject.TypeLiteral;
import com.google.inject.matcher.Matchers;
import com.google.inject.spi.TypeEncounter;
import com.google.inject.spi.TypeListener;
/**
 * Log4J Logger Inject config Module
 */
public final class LoggerInjectModule extends AbstractModule{
   /*
    * @see com.google.inject.AbstractModule#configure()
    */

   @Override
   protected void configure(){
      bindListener(Matchers.any(),new Log4JTypeListener());
      // ←下記コメントのとおり追加しても良い。
   }
   class Log4JTypeListener implements TypeListener{
      /*
       * @see com.google.inject.spi.TypeListener#hear(com.google.inject.TypeLiteral, com.google.inject.spi.TypeEncounter)
       */

      @Override
      public <T>void hear(TypeLiteral<T> typeLiteral,TypeEncounter<T> typeEncounter){

         for(Field field : typeLiteral.getRawType().getDeclaredFields()){
            if (field.getType()==Logger.class && field.isAnnotationPresent(InjectLogger.class)){
               // Logger変数で、@InjectLogger が付いてるもの
               typeEncounter.register(new Log4JMembersInjector<T>(field));
            }
      /*****************************************************************
             * この if に、else節を追加して他の型変数+アノテーションを条件に
             * 同様の TypeEncounter#register でのインジェクト定義を登録
             * できるはず。
             *    → その場合は、class Log4JTypeListener と
             *       class LoggerInjectModule のクラス名を変更すべき
             *       configure() に、bindListener 実行をさらに追加
             *****************************************************************/

         }
      }
      // とりあえず、インナークラスで。
      class Log4JMembersInjector<T> implements MembersInjector<T>{
         private final Field field;
         private final Logger logger;
         Log4JMembersInjector(Field field){
            this.field = field;
            this.logger = Logger.getLogger(field.getDeclaringClass());
            this.field.setAccessible(true);
         }
         /*
          * @see com.google.inject.MembersInjector#injectMembers(java.lang.Object)
          */

         @Override
         public void injectMembers(T t){

            try{
            this.field.set(t,this.logger);
            }catch(IllegalAccessException e){
               throw new RuntimeException(e);
            }
         }
      }

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

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface InjectLogger{
}
-------------------------------------------------------------
public class Sample{
   @InjectLogger Logger logger;
-------------------------------------------------------------
Injector injector = Guice.createInjector(new LoggerInjectModule());
Sample s = injector.getInstance(Sample.class);
-------------------------------------------------------------
createInjector で指定する。
Logger 以外にインジェクト対象をこの bindListener 使用追加
した場合のクラス名称は悩むところである。