2010-11-21 9 views
5

Контекст: Новый класс, который говорит Bar, вводится в JVM во время выполнения. Этот класс принадлежит к пакету say com.foo. Ссылка на этот класс вводится в другой класс, который принадлежит к одному и тому же пакету. Новый класс может иметь другое имя при каждом его загрузке - поэтому это не может быть указано как часть любого файла конфигурации - например, не может быть указан в файле build.xml, который будет включен как часть файла jar.Настройка класса для недавно введенного класса

Вопрос: В момент загрузки класса jvm выдает ошибку - java Результат 1. Хотя я не могу окончательно определить основную причину, похоже, что недавно введенный класс не найден загрузчиком класса. Сервер был запущен в подробном режиме, который показывает список классов, загружаемых JVM, и этот новый введенный класс отображается загруженным.

Вопрос: Является ли недавно введенный класс уже в пути к классам? Если нет, как установить его?

[Изменить] - добавление некоторого кода в вопрос.

Сегмент кода - 1: Этот сегмент кода ниже вызывается из метода PreMain. Метод Premain будет вызываться агентом JVM и будет вводить ссылку на аппаратуру во время выполнения. Метод Premain вводит 1 новый класс - Bar - и 1 ссылку на этот новый класс из метода - returnsABool() - в существующий класс - ExistingClass.

public static void premain(String agentArgs, Instrumentation inst) { 

     // 1. Create and load the new class - Bar 
     String className = "Bar"; 
     byte [] b = getBytesForNewClass(); 
     //override classDefine (as it is protected) and define the class. 
     Class clazz = null; 
     try { 
      ClassLoader loader = ClassLoader.getSystemClassLoader(); 
      Class cls = Class.forName("java.lang.ClassLoader"); 
      java.lang.reflect.Method method = 
      cls.getDeclaredMethod("defineClass", new Class[] { String.class, byte[].class, int.class, int.class }); 
      // protected method invocation 
      method.setAccessible(true); 
      try { 
      Object[] args = new Object[] { className, b, new Integer(0), new Integer(b.length)}; 
      clazz = (Class) method.invoke(loader, args); 
      } finally { 
      method.setAccessible(false); 
      } 
     } catch (Exception e) { 
     System.err.println(
      "AllocationInstrumenter was unable to create new class" + e.getMessage()); 
     e.printStackTrace(); 
     } 

     // 2. Inject some lines of code into the returnsABool method in ExistingClass class that references Bar 
     inst.addTransformer(new CustomInstrumenter(), true); 

     // end of premain method 
} 

код Sement 2: Метод returnsABool() должен быть байт-впрыскивают с прокомментированных линий, показанных ниже. Код для ввода байта также вызывается из метода PreMain.

public class ExistingClass{ 

    public static boolean returnsABool() { 
    // Code within comments is byte-injected, again as part of the pre-main method 

    /* 
    String str = Bar.get(); 
    if (str != "someValue") { 
     return true; 
    } 
    */ 

     return false; 
    } 
} 

Байт впрыска код ExistingClass - сделано с использованием библиотеки ассемблера

{ 
    MethodVisitor mv = cv.visitMethod(access, name, desc, signature, exceptions); 
    mv.visitCode(); 
    Label l0 = new Label(); 
    mv.visitLabel(l0); 
    mv.visitMethodInsn(Opcodes.INVOKESTATIC, "com/Bar", "get", "()Ljava/lang/String;");   
    mv.visitLdcInsn("some constant here"); 
    Label l1 = new Label(); 
    mv.visitJumpInsn(Opcodes.IF_ACMPNE, l1); 
    mv.visitInsn(Opcodes.ICONST_0); Label l2 = new Label(); 
    mv.visitJumpInsn(Opcodes.GOTO, l2); 
    mv.visitLabel(l1); 
    mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null); 
    mv.visitInsn(Opcodes.ICONST_1); 
    mv.visitFrame(Opcodes.F_SAME1, 0, null, 1, new Object[] {Opcodes.INTEGER}); 
    mv.visitInsn(Opcodes.IRETURN); 
    mv.visitMaxs(2, 0); 
    mv.visitEnd(); 
} 
+0

Как, в частности, класс, который «вводится»? Динамически создается и загружается загрузчиком классов? –

+0

Некоторый код Java был бы полезен, в противном случае очень сложно помочь вам. Кроме того, может быть, этот вопрос будет полезен: http://stackoverflow.com/q/4210346/74694 –

+3

Покажите минимальный пример, демонстрирующий проблему, которая у вас есть. –

ответ

1

Я подозреваю, у вас есть что-то не так с вашим поколением байт-кода, следующий код ASM работает для меня:

 mv.visitCode(); 
     Label l0 = new Label(); 
     mv.visitLabel(l0); 
     mv.visitMethodInsn(Opcodes.INVOKESTATIC, "com/Bar", "get", "()Ljava/lang/String;"); 
     Label l1 = new Label(); 
     mv.visitLdcInsn("some constant here"); 
     mv.visitJumpInsn(Opcodes.IF_ACMPEQ, l1); 
     mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null); 
     mv.visitInsn(Opcodes.ICONST_1); 
     mv.visitFrame(Opcodes.F_SAME, 0, null, 1, new Object[] {Opcodes.INTEGER}); 
     mv.visitInsn(Opcodes.IRETURN); 
     mv.visitLabel(l1); 
     mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null); 
     mv.visitInsn(Opcodes.ICONST_0); 
     mv.visitFrame(Opcodes.F_SAME, 0, null, 1, new Object[] {Opcodes.INTEGER}); 
     mv.visitInsn(Opcodes.IRETURN); 
     mv.visitMaxs(2, 1); 
     mv.visitEnd(); 

Также обратите внимание, что:

  • так, как вы сравниваете строк, скорее всего, приведет к проблемам, вы должны использовать str.equals(str2)
  • вы заменяете весь метод, вместо того, чтобы впрыскивать свой собственный код в начале (ваши комментарии, кажется, указывают, что вы хотите, чтобы ввести , вместо замены)
+0

Фантастический - спасибо Ниэму - это (использование равных) решило проблему - урок усвоил трудный путь! –

+0

Чтобы завершить ответ, похоже, что классы, введенные во время выполнения, уже находятся в пути к классу. –

+0

Какой инструмент вы использовали для создания вышеуказанного кода? –

Смежные вопросы