Javassist

日経225

package aop;
import java.util.*;
import java.lang.reflect.*;
import javassist.*;

public class TestJavassist
{  
  public static void main(String[] args) throws Exception
  {
    ClassLoader usingClassLoader = Thread.currentThread().getContextClassLoader();
//    System.out.println( usingClassLoader );
    
    ClassPool pool = new ClassPool(true);
    CtClass ctSuper = pool.get("java.util.ArrayList");
    CtClass ctProxy = pool.makeClass("$$AopProxy$$",ctSuper);
    
    Method add = java.util.ArrayList.class.getMethod("add", new Class[]{Object.class});
    CtMethod ctAdd = CtNewMethod.make(
        add.getModifiers()
        , toCtClass(pool,add.getReturnType())
        , add.getName()
        , toCtClassArray(pool,add.getParameterTypes())
        , toCtClassArray(pool,add.getExceptionTypes())
        , "{ System.out.println(\"[BEFORE]\\n\" + aop.TestJavassist#dumpParams($args) ); return ($r)super.add($$); }"
        , ctProxy
        );
    ctProxy.addMethod(ctAdd);

    Class proxyType = ctProxy.toClass( usingClassLoader );
    pool = null;



    ArrayList list = (ArrayList)proxyType.newInstance();
    list.add("aaa");
  }
  ////////////////////////////////////////////////////////
  public static CtClass toCtClass(ClassPool pool, Class src) throws NotFoundException
  {
    return pool.get(toString(src));
  }
  public static CtClass[] toCtClassArray(ClassPool pool, Class[] src) throws NotFoundException
  {
    String[] srcs = new String[src.length];
    for(int i=0, len=src.length; i<len; ++i)
      srcs[i] = toString(src[i]);
    return pool.get(srcs);
  }
  public static String toString(Class type)
  {
    return type.isArray()
      ? toString( type.getComponentType() ) + "[]" : type.getName();
  }
  public static String dumpParams(Object[] params)
  {
    if( params == null || params.length == 0 )
      return "";
    
    StringBuffer b = new StringBuffer(1024);
    for(int i=0, len=params.length; i<len; ++i)
    {
      b.append("[").append(i).append("]type='");
      if( params[i] == null )
        b.append("', value='null'\n");
      else
        b.append( toString(params[i].getClass()) ).append("', value='").append( params[i] ).append("'");
    }
    return b.toString();
  }
}

実行結果

[BEFORE]
[0]type='java.lang.String', value='aaa'

aopalliance のMethodInterceptorやMethodInvocationインターフェースを突っ込めるようにするには、Javassistの用意している変数だけではむりっぽそうだ。少々面倒な文字列操作が必要か。