Я использую ASM library для изменения байт-кода, созданного другими пользователями. Для произвольного метода в произвольном классе я хотел бы создать LdcInsnNode
, который добавляет текущий класс в стек.Как создать ASM LdcInsnNode, который статически добавляет текущий класс в стек?
Например, допустим, что я преобразовываю класс под названием com.example.ExampleClass
. Я хотел бы создать байт-код, который эквивалентен System.out.println(ExampleClass.class.getName());
.
Это похоже на относительно простую задачу. Когда я использую рамочную плагин Eclipse, байт-код, он говорит, что следующий байт-код эквивалентен:
GETSTATIC java/lang/System.out : Ljava/io/PrintStream;
LDC Lcom/example/ExampleClass;.class
INVOKEVIRTUAL java/lang/Class.getName()Ljava/lang/String;
INVOKEVIRTUAL java/io/PrintStream.println (Ljava/lang/Object;)V
Я попытался следующий код:
private InsnList printClass() {
InsnList result = new InsnList();
result.add(new FieldInsnNode(Opcodes.GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;"));
result.add(new LdcInsnNode("L" + name + ";.class"));
result.add(new MethodInsnNode(Opcodes.INVOKEVIRTUAL, "java/lang/Class", "getName", "()Ljava/lang/String;", false));
result.add(new MethodInsnNode(Opcodes.INVOKEVIRTUAL, "java/io/PrintStream", "println", "(Ljava/lang/String;)V", false));
return result;
}
Это время запуска в расширении ClassNode
, так name
относится к полю ClassNode.name
. Возвращаемый этим методом InsnList
вставляется перед существующим AbstractInsnNode
с использованием InsnList.insertBefore(AbstractInsnNode, printClass())
. Когда эта точка будет достигнута в байткоде, я получаю сообщение об ошибке со следующей причиной:
Type 'java/lang/String' (current frame, stack[1]) is not assignable to 'java/lang/Class'
Это ясно, потому что команда LDC является добавлением строки "Lcom/example/ExampleClass;.class"
вместо фактического класса Lcom/example/ExampleClass;.class
.
Есть ли обходной путь для этого? Кажется невозможным напрямую добавить объект Class
в LdcInsnNode
, потому что класс еще не существует. Но есть ли способ добавить инструкцию, которая загружает объект Class
?
В моем конкретном случае вызов метода Object.getClass()
не является вариантом, поскольку он должен работать из статического контекста.