установка пути к классам для недавно введенного класса

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

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

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

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

Сегмент кода — 1: этот сегмент кода ниже вызывается из метода PreMain — метод Premain будет вызываться агентом JVM и вводить ссылку на инструментарий во время выполнения. Метод Premain вводит 1 новый класс — Bar — и 1 ссылку на этот новый класс из метода — returnABool() — в существующий класс — 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
}

Сегмент кода 2: метод returnABool() должен быть дополнен байтовыми инъекциями строк с комментариями, показанными ниже. Код для ввода байта this также вызывается из метода 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 — выполняется с использованием библиотеки asm

{  
    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();   
}

person crazy horse    schedule 21.11.2010    source источник
comment
Как именно внедряется класс? Создается ли он динамически и загружается загрузчиком классов?   -  person Bert F    schedule 21.11.2010
comment
Немного java кода было бы полезно, иначе очень сложно вам помочь. Кроме того, возможно, этот вопрос будет полезен: stackoverflow.com/q/4210346/74694   -  person Neeme Praks    schedule 21.11.2010
comment
Покажите минимальный пример, демонстрирующий проблему, с которой вы столкнулись.   -  person Thorbjørn Ravn Andersen    schedule 21.11.2010
comment
Берт, да, этот динамический класс создается и загружается загрузчиком классов.   -  person crazy horse    schedule 22.11.2010
comment
@Neeme, @Thorjam, я включил фрагменты кода Java   -  person crazy horse    schedule 22.11.2010
comment
@crazy horse: ваш код неправильно отформатирован, используйте кнопку 01010101. И было бы полезно, если бы вы указали, для чего предназначен этот код.   -  person Neeme Praks    schedule 22.11.2010
comment
Я опробовал ваш код внедрения системного загрузчика классов и, по крайней мере, при нормальных обстоятельствах (простой основной метод), похоже, он работает нормально (я использовал байт-код, сгенерированный javac). Поэтому я бы заподозрил вашу логику генерации байт-кода. Или как вы вводите код в ExistingClass?   -  person Neeme Praks    schedule 22.11.2010
comment
Так же jvm выдает ошибку - java Result 1 не очень информативный. Может быть, вы можете добавить более подробную информацию о полученной ошибке?   -  person Neeme Praks    schedule 22.11.2010
comment
@ Нееме, спасибо. К сожалению, я не вижу подробного сообщения об ошибке. Когда я запускаю сценарий ANT, все, что я вижу, это результат Java 1.   -  person crazy horse    schedule 22.11.2010
comment
@Neeme, добавлена ​​​​вставка байтов для ExistingClass   -  person crazy horse    schedule 22.11.2010
comment
@Neeme, добавлена ​​​​вставка байтов для ExistingClass   -  person crazy horse    schedule 22.11.2010
comment
Можно ли демистифицировать результат Java 1. с помощью приведенной здесь техники: stackoverflow.com/questions/4230940/   -  person Martin Algesten    schedule 23.11.2010
comment
Я бы посоветовал вам пока избавиться от агента и запустить тот же код из обычного основного метода. Может быть, это будет иметь лучшую обработку ошибок?   -  person Neeme Praks    schedule 23.11.2010
comment
@Neeme, @Martin, да, согласен - я пока избавлюсь от агента и попробую его в основном методе. Я сейчас не в городе, попробую, когда вернусь. Цените ваши предложения.   -  person crazy horse    schedule 23.11.2010


Ответы (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)
  • вы заменяете весь метод вместо того, чтобы вводить свой пользовательский код в начале (ваши комментарии, похоже, указывают на то, что вы хотите внедрить, а не заменить)
person Neeme Praks    schedule 23.11.2010
comment
Фантастически - спасибо, Ниме - это (использование равных) решило проблему - урок усвоился на собственном горьком опыте! - person crazy horse; 28.11.2010
comment
Чтобы завершить ответ, похоже, что классы, введенные во время выполнения, уже находятся в пути к классам. - person crazy horse; 28.11.2010
comment
@crazy horse: я использовал плагин ASM Eclipse (asm.ow2.org/eclipse/index.html) и немного подправил сгенерированный код, чтобы он больше походил на ваш. - person Neeme Praks; 07.12.2010