1. 程式人生 > >javaassist修改constructor建構函式,增加方法,修改方法

javaassist修改constructor建構函式,增加方法,修改方法

public class SimplePrincipal implements Principal, Serializable
   35   {
   36      private static final long serialVersionUID = 7701951188631723261L;
   37      private final String name;
   38   
   39      public SimplePrincipal(String name)
   40      {
   41         this.name = name;

   42      }

ClassPool cp = ClassPool.getDefault();
CtClass cc = cp.get("org.jboss.security.SimplePrincipal");
CtConstructor ctc = cc.getConstructors()[0];
ctc.setBody("{name=\"modify name\";this.name = name;}");
SimplePrincipal sp=(SimplePrincipal)cc.toClass().getConstructor(String.class).newInstance("name");

System.out.println(sp.getName());

SimplePrincipal pp=new SimplePrincipal("ww");
System.out.println(pp.getName());

輸出

modify name

modify name

應該是整個classloader的simpleprincipal都被改了

為了保證只有當前的SimplePrincipal被修改

ClassPool cp = ClassPool.getDefault();
CtMethod m=CtNewMethod.make("public void modifyName(String name);", cc);CtClass cc = cp.get("org.jboss.security.SimplePrincipal");
CtMethod m=CtNewMethod.make("public void modifyName(String name);", cc);

m.setBody("{this.name= $1;}");  
cc.addMethod(m);
Object sp=cc.toClass().getConstructor(String.class).newInstance("name");

Method mm=sp.getClass().getDeclaredMethod("modifyName",String.class);
mm.invoke(sp, "hello");
System.out.println(((SimplePrincipal)sp).getName());

SimplePrincipal pp=new SimplePrincipal("ww");
System.out.println(pp.getName());

這裡的setBody中的$1是指第一個引數(javaassist的規則)

輸出

hello

ww

如果想修改己有方法的內容

CtMethod cm = ... ;
cm.instrument(
    new ExprEditor() {
        public void edit(MethodCall m)
                      throws CannotCompileException
        {
            if (m.getClassName().equals("Point")
                          && m.getMethodName().equals("move"))
                m.replace("{ $1 = 0; $_ = $proceed($$); }");
        }
    });

exprEditor沒有細細研究,以後有機會研究再更新吧

attempted  duplicate class definition for name

這個錯誤是因為同一個classloader載入了兩次SimplePrincipal

因為javaassist是在執行期前修改的位元組碼