Получить java.lang.IllegalAccessError при доступе к частному полю внешнего класса через ASM Java Bytecode

в отражении к приватному полю можно получить доступ через getDeclaredField() и setAccessible(true). Как получить доступ к частному полю внешнего класса через API байт-кода Objectweb ASM? Я установил, чтобы получить приватное поле из чего-то вроде, через

Field current = sourceObject.getDeclaredField(privateFieldName);
Field.setAccessible(true);
Type sourceType = Type.getType(sourceObject.getClass());
mv.visitFieldInsn(Opcodes.GETFIELD,
                  sourceType.getInternalName(),
                  privateFieldname,
                  Type.getDescriptor(current.getType()));

При выполнении байт-кода и получении приватного поля я всегда получал ошибку "java.lang.IllegalAccessError"

Любая подсказка? Спасибо,


person erwin davis    schedule 17.09.2010    source источник


Ответы (2)


Вы не можете сделать это так. setAccessible(true) повлияет только на текущую ссылку на поле в текущем выполнении вашей программы (то есть не повлияет на выполнение результирующей модифицированной программы).

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

Чтобы получить доступ к частному полю YourClass.thePrivatefield некоторого объекта, хранящегося в локальной переменной varId, вы делаете что-то вроде

// Get hold of the field-reference
mv.visitLdcInsn(Type.getType("LYourClass;"));
mv.visitLdcInsn("thePrivateField");
mv.visitMethodInsn(INVOKEVIRTUAL,
                   "java/lang/Class",
                   "getDeclaredField",
                   "(Ljava/lang/String;)Ljava/lang/reflect/Field;");

// Duplicate the reference
mv.visitInsn(DUP);

// Call setAccessible(true) using the first reference.
mv.visitInsn(ICONST_1);
mv.visitMethodInsn(INVOKEVIRTUAL,
                   "java/lang/reflect/Field",
                   "setAccessible",
                   "(Z)V");

// Call get(yourObject) using the second reference to the field.
mv.visitInsn(ALOAD, varId);
mv.visitMethodInsn(INVOKEVIRTUAL,
                   "java/lang/reflect/Field",
                   "get",
                   "(Ljava/lang/Object;)Ljava/lang/Object;");

Если поле, которое вы пытаетесь сделать доступным, является частью базы cobe, которую вы переписываете, вы, очевидно, также можете сделать это поле общедоступным, используя ACC_PUBLIC вместо ACC_PRIVATE.

person aioobe    schedule 01.10.2010
comment
Здорово. Я попробую. Кстати, это Java ASM или BCEL? Спасибо - person erwin davis; 05.10.2010

Настоящая проблема заключается в том, что вы не можете легально получить доступ к этим переменным. Это связано с тем, что JVM определила свои правила доступа до того, как в Java появились внутренние классы, поэтому javac создает синтетические методы доступа для полей, к которым он не может иметь законный доступ в JVM, но может в Java. Например,

class Sample {
    private int i = 0;
    class Inner {
        int foo = i;
    }
}

Затем мы можем использовать javap для декомпиляции сгенерированных классов.

fowles@morbo:/tmp$ javap -private Sample
Compiled from "Sample.java"
class Sample extends java.lang.Object{
    private int i;
    Sample();
    static int access$000(Sample);
}

fowles@morbo:/tmp$ javap -c Sample.Inner
Compiled from "Sample.java"
class Sample$Inner extends java.lang.Object{
int foo;

final Sample this$0;

Sample$Inner(Sample);
  Code:
   0:   aload_0
   1:   aload_1
   2:   putfield    #1; //Field this$0:LSample;
   5:   aload_0
   6:   invokespecial   #2; //Method java/lang/Object."<init>":()V
   9:   aload_0
   10:  aload_0
   11:  getfield    #1; //Field this$0:LSample;
   14:  invokestatic    #3; //Method Sample.access$000:(LSample;)I
   17:  putfield    #4; //Field foo:I
   20:  return

}

Обратите внимание на метод access$000(Sample), сгенерированный в Sample и использованный в Sample.Inner. К сожалению, ваши варианты либо

  1. Сделайте поле доступным
  2. Использовать отражение
  3. Создание синтетических средств доступа
person Matt    schedule 16.03.2011