2016-11-27 2 views
0

Мне нужно изменить следующий класс во время выполнения, чтобы напечатать значение переменной экземпляра «count» в конце каждого метода.Печать переменной экземпляра с помощью javasssist

package test.hib.javaassist; 

import java.io.IOException; 

import javassist.CannotCompileException; 
import javassist.ClassPool; 
import javassist.CtClass; 
import javassist.CtMethod; 
import javassist.NotFoundException; 

public class JavaAssistTest { 

    int count; 


    public void doSomething1(){ 
     count++; 
    } 

    public void doSomething2(){ 
     count++; 
    } 

    public void doSomething3(){ 
     count++; 
    } 

    public void doSomething4(){ 
     count++; 
    } 

} 

После основной класс, где я пытаюсь изменить байт-код с помощью javaassist.

package test.hib.javaassist; 

import java.io.IOException; 

import javassist.CannotCompileException; 
import javassist.ClassPool; 
import javassist.CtClass; 
import javassist.CtMethod; 
import javassist.NotFoundException; 

public class Main { 

    public static void main(String[] args) throws NotFoundException, CannotCompileException, IOException { 

     ClassPool pool = ClassPool.getDefault(); 
     CtClass cc = pool.get("test.hib.javaassist.JavaAssistTest"); 
     CtMethod[] methods = cc.getDeclaredMethods(); 

     for(CtMethod method : methods){ 
      if(! (method.getName().equals("main"))){ 
       method.insertAfter("{System.out.println(count);}"); 
       //method.insertAfter("System.out.println($type);"); 
      } 
     } 

     cc.writeFile(); 

     System.out.println("Completed editting"); 

     JavaAssistTest test = new JavaAssistTest(); 
     test.doSomething1(); 
     test.doSomething2(); 
     test.doSomething3(); 
     test.doSomething4(); 

     System.out.println("Finished"); 

    } 

} 

В настоящее время печати

Completed editting 
Finished 

Я хочу, чтобы напечатать

Completed editting 
1 
2 
3 
4 
Finished 

Можете ли вы pointout ошибку в моем коде?

+0

Я бы предположил, что класс уже загружен, поэтому изменения в файле .class не будут отображаться во время выполнения текущей JVM. Вы можете попробовать перезагрузить класс, как описано, например. здесь: http://stackoverflow.com/a/3971771/281108 –

+0

hmm .... выглядит сложно. Я попробовал другой способ загрузки класса. \t \t Класс testClass = Loader.getSystemClassLoader(). LoadClass ("test.hib.javaassist.JavaAssistTest"); \t \t JavaAssistTest test = (JavaAssistTest) testClass.newInstance(); Но никаких изменений в результатах! – Renjith

+0

Я уверен, что не перезагрузит класс, если он уже загружен. –

ответ

1

API Javassist здесь немного запутан. Посмотрите на реализацию writeFile. Это ярлык для writeFile("."), который сохраняет класс в каталоге программы, а не в пути к классу. Вы ожидаете, что он переопределит исходный файл класса, что этот метод не делает. Ваш загрузчик системного класса не сможет найти обновленный файл класса.

Вы можете вручную сохранить файл класса в нужном месте с помощью writeFile(String) или принудительно загрузить модифицированный класс, вызвав cc.toClass(), что вынуждает загрузку модифицированного класса до того, как ваш загрузчик классов будет выглядеть вручную.

+0

Спасибо! cc.toClass() работал. В конце концов, я должен использовать это в приложении, развернутом на Tomcat Server. Но в документе Java дано то же самое не применимо для приложений, запущенных на сервере приложений. Я должен попробовать использовать 'toClass (java.lang.ClassLoader loader)'. – Renjith