2008/01/04 の投稿 アノテーション

**** インターフェースの定義
public interface Planet{
   public void see();
}
**** 抽象クラスの定義
public abstract class AbstractPlanet implements Planet{
   /* (非 Javadoc)
    * @see Planet#see()
    */
   @Prefunction("pre")
   @Aftfunction("aft")
   public void see(){
      System.out.println("AbstractPlanet#see()");
   }
   public boolean pre(){
      System.out.println("AbstractPlanet#pre()");
      return true;
   }
   public boolean aft(){
      System.out.println("AbstractPlanet#aft()");
      return true;
   }
}
**** 前処理アノテーション @Aftfunctionも同様
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.METHOD)
public @interface Prefunction{
   String value();
}
**** プロキシされるクラスのインターフェース
public interface Neptune extends Planet{
   public void foo(String s);
}
**** Neptuneの実装 and AbstractPlanetの具象
class NeptuneImpl extends AbstractPlanet implements Neptune{
   @DefSatellite private String satellite;
   /*
    * @see Neptune#foo(java.lang.String)
    */
   @Prefunction("pre")
   @Aftfunction("aft")
   public void foo(String s){
      System.out.println("Neptune#foo() s="+s);
      System.out.println("Neptune#satellite="+satellite);
   }
}
**** Field に付けるアノテーション 
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 DefSatellite{
}
**** プロキシ
import java.lang.reflect.Field;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

public class PlanetProxy implements InvocationHandler{
   private Object target;
   private PlanetProxy(Planet obj){
      this.target = obj;
   }
   public final static Object create(Planet obj){
      return Proxy.newProxyInstance(obj.getClass().getClassLoader()
                                    ,obj.getClass().getInterfaces()
                                    ,new PlanetProxy(obj));
   }
   public final static Neptune createNeptune(){
      Planet obj = new NeptuneImpl();
      return (Neptune)Proxy.newProxyInstance(obj.getClass().getClassLoader()
                                    ,obj.getClass().getInterfaces()
                                    ,new PlanetProxy(obj));
   }
   /*
    * @see java.lang.reflect.InvocationHandler
    * #invoke(java.lang.Object, java.lang.reflect.Method, java.lang.Object)
    */
   public Object invoke(Object proxy,Method m,Object
 args) throws Throwable{
      if (proxy==null){throw new IllegalArgumentException("proxy is null");}
      
      Field satelliteField = null;  // satellie変数 Field
      Field[] fls = this.target.getClass().getDeclaredFields();
      for(int i=0;i < fls.length;i++){
         if (fls[i].getAnnotation(DefSatellite.class)!=null){
            satelliteField = fls[i];
            break;
         }
      }
      if (satelliteField != null){
         // satellie変数 Field に値をセット
         satelliteField.setAccessible(true);
         satelliteField.set(this.target,"satellite_Moon");
      }
      Method targetMethod = this.target.getClass()
                            .getMethod(m.getName(),m.getParameterTypes());
      try{
      Prefunction pre = targetMethod.getAnnotation(Prefunction.class);
      if (pre != null){
         System.out.println("■ pre");
         Method mt = this.target.getClass().getMethod(pre.value());
         if (((Boolean)mt.invoke(this.target)).booleanValue()){
            return m.invoke(this.target,args);
         }
      }else{
         return m.invoke(this.target,args);
      }
      return null;
      }finally{
         Aftfunction aft = targetMethod.getAnnotation(Aftfunction.class);
         if (aft != null){
            System.out.println("■ after");
            Method mt = this.target.getClass().getMethod(aft.value());
            mt.invoke(this.target);
         }  
      }
   }
}
**** 呼び出し実行
  Neptune pl = PlanetProxy.createNeptune();
  pl.foo("test");
  pl.see();