Динамический инструментарий байт-кода - проблема

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

Link

, Если Вы используете Angular2, этот путь работы:

Click me.

Посмотрите здесь https://stackoverflow.com/a/45465728/2803344

6
задан Joachim Sauer 6 August 2009 в 09:42
поделиться

1 ответ

Я не обнаружил никаких проблем, когда преобразовал B до A в Sun 1.6.0_15 и 1.5.0_17 JRE (я использовал ASM ). Я бы дважды проверил код преобразования, запустив его извне и проверив результирующие классы (например, с помощью javap). Я бы также проверил вашу конфигурацию пути к классам, чтобы убедиться, что A не загружен перед вашим агентом по какой-то причине (возможно, проверьте ваш preain с помощью getAllLoadedClasses ).


EDIT:

Если вы загрузите class в вашем агенте выглядит следующим образом:

Class.forName("A");

... тогда возникает исключение:

Exception in thread "main" java.lang.NoSuchMethodError: B.print()V

Это имеет смысл - становится зависимостью агента, и это не имеет смысла чтобы агент инструментировал свой собственный код. Вы получите бесконечный цикл, который приведет к переполнению стека. Следовательно, не обрабатывается ClassFileTransformer .


Для полноты, вот мой тестовый код, который работает без проблем. Как уже упоминалось, это зависит от библиотеки ASM.

Агент:

public class ClassModifierAgent implements ClassFileTransformer {

  public byte[] transform(ClassLoader loader, String className,
      Class<?> classBeingRedefined, ProtectionDomain protectionDomain,
      byte[] classfileBuffer) throws IllegalClassFormatException {
    System.out.println("transform: " + className);
    if ("A".equals(className)) {
      return new AModifier().modify(classfileBuffer);
    }
    if ("B".equals(className)) {
      return new BModifier().modify(classfileBuffer);
    }
    return classfileBuffer;
  }

  /** Agent "main" equivalent */
  public static void premain(String agentArguments,
      Instrumentation instrumentation) {
    instrumentation.addTransformer(new ClassModifierAgent());
  }

}

Инжектор метода для A :

public class AModifier extends Modifier {

  @Override
  protected ClassVisitor createVisitor(ClassVisitor cv) {
    return new AVisitor(cv);
  }

  private static class AVisitor extends ClassAdapter {

    public AVisitor(ClassVisitor cv) { super(cv); }

    @Override
    public void visitEnd() {
      MethodVisitor mv = cv.visitMethod(Opcodes.ACC_PUBLIC, "print", "()V",
          null, null);
      mv.visitCode();
      mv.visitFieldInsn(Opcodes.GETSTATIC, "java/lang/System", "out",
          "Ljava/io/PrintStream;");
      mv.visitLdcInsn("X");
      mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/io/PrintStream",
          "println", "(Ljava/lang/String;)V");
      mv.visitInsn(Opcodes.RETURN);
      mv.visitMaxs(2, 1);
      mv.visitEnd();

      super.visitEnd();
    }

  }

}

Заменитель метода для B :

public class BModifier extends Modifier {

  @Override
  protected ClassVisitor createVisitor(ClassVisitor cv) {
    return new BVisitor(cv);
  }

  class BVisitor extends ClassAdapter {

    public BVisitor(ClassVisitor cv) { super(cv); }

    @Override
    public MethodVisitor visitMethod(int access, String name, String desc,
        String signature, String[] exceptions) {
      if ("foo".equals(name)) {
        MethodVisitor mv = cv.visitMethod(Opcodes.ACC_PUBLIC, "foo", "()V",
            null, null);
        mv.visitCode();
        mv.visitVarInsn(Opcodes.ALOAD, 0);
        mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "B", "print", "()V");
        mv.visitInsn(Opcodes.RETURN);
        mv.visitMaxs(1, 1);
        mv.visitEnd();
        return new EmptyVisitor();
      } else {
        return super.visitMethod(access, name, desc, signature, exceptions);
      }
    }
  }
}

Общий базовый код :

public abstract class Modifier {

  protected abstract ClassVisitor createVisitor(ClassVisitor cv);

  public byte[] modify(byte[] data) {
    ClassReader reader = new ClassReader(data);
    ClassWriter writer = new ClassWriter(reader, ClassWriter.COMPUTE_FRAMES);
    ClassVisitor visitor = writer;
    visitor = new CheckClassAdapter(visitor);
    visitor = createVisitor(visitor);
    reader.accept(visitor, 0);
    return writer.toByteArray();
  }

}

Для некоторых видимых результатов я добавил System.out.println ('X'); в A.print () .

При запуске с этим кодом :

public class MainInstrumented {
  public static void main(String[] args) {
    new B().foo();
  }
}

... выводит следующий результат:

transform: MainInstrumented
transform: B
transform: A
X
8
ответ дан 16 December 2019 в 21:44
поделиться
Другие вопросы по тегам:

Похожие вопросы: