2016-02-03 9 views
0

Я пытаюсь вставить обратный вызов в метод Java с использованием BCEL, но обратный вызов никогда не вызывается. Программы работают так, как будто это вообще не инструмент.BCel исправление метода на лету не работает

усеченный версию того, что я сделал:

package com.github.worldsender; 

import java.lang.reflect.InvocationTargetException; 

import org.apache.bcel.*; 
import org.apache.bcel.classfile.*; 
import org.apache.bcel.generic.*; 

public class CustomHook { 
    public static void callback() { 
     System.out.println("Success"); 
    } 

    private static JavaClass getOriginal() { 
     try { 
      return Repository.lookupClass("com.github.worldsender.Foo"); 
     } catch (ClassNotFoundException e) { 
      throw new RuntimeException("Foo not found.", e); 
     } 
    } 

    private static ClassGen modClass(ClassGen classGen) { 
     for (Method method : classGen.getMethods()) { 
      if (!method.getName().equals("main")) 
       continue; 
      classGen.removeMethod(method); 
      MethodGen methodGen = modConstructor(classGen, method); 
      classGen.addMethod(methodGen.getMethod()); 
      methodGen.getInstructionList().dispose(); 
      return classGen; 
     } 
     throw new RuntimeException("Method not found, abort"); 
    } 

    private static MethodGen modConstructor(ClassGen classGen, Method constructor) { 
     InstructionFactory factory = new InstructionFactory(classGen); 
     ConstantPoolGen constants = classGen.getConstantPool(); 
     MethodGen methodGen = new MethodGen(constructor, classGen.getClassName(), constants); 

     InstructionList ilist = methodGen.getInstructionList(); 

     String invokedClass = "com.github.worldsender.CustomHook"; 
     String invokedMethod = "callback"; 
     Type returnType = Type.VOID; 
     Type[] arguments = Type.NO_ARGS; 
     short invokeType = Constants.INVOKESTATIC; 
     InvokeInstruction invoke = factory.createInvoke(invokedClass, invokedMethod, returnType, arguments, invokeType); 

     ilist.insert(invoke); 
     methodGen.stripAttributes(true); 
     methodGen.setMaxStack(); 
     methodGen.setMaxLocals(); 
     return methodGen; 
    } 

    public static void main(String[] args) throws Exception { 
     JavaClass original = getOriginal(); 
     ClassGen modClass = new ClassGen(original); 
     modClass = modClass(modClass); 

     Repository.removeClass(original); 
     Repository.addClass(modClass.getJavaClass()); 

     Class<?> minecraftMain = Class.forName("com.github.worldsender.Foo"); 

     java.lang.reflect.Method meth = minecraftMain.getMethod("main", String[].class); 
     meth.invoke(null, (Object) args); 
    } 
} 
//// Other class 
package com.github.worldsender; 

public class Foo { 
    public static void main(String[] args) { 
     System.out.println("Here"); 
    } 
} 

Все, что отпечатанный:

Here 

То, что я ожидал был:

Success 
Here 

Что я делаю неправильно ?

ответ

1

При вызове

Repository.addClass(modClass.getJavaClass()) 

вы добавляете класс в хранилище BCEL, но не к классу пути текущей виртуальной машины. При звонке

Class.forName("com.github.worldsender.Foo") 

вы, тем не менее, поручаете виртуальной машине загрузить файл немодифицированного класса из пути к классу. Поэтому вы не можете наблюдать никакого эффекта. Посмотрите на BCEL's built-in class loader для загрузки сгенерированного класса.