Установить приватное поле класса пакета-частного из внешнего класса пакета с отражением - PullRequest
0 голосов
/ 04 декабря 2018

Мне нужно изменить значение закрытой переменной в классе частного пакета из класса внешнего пакета.

  • package: java.util.jar из jdk-9.0.1
  • класс: JarVerifier.java
  • переменная: parsingBlockOrSF (private boolean)

Я пробовал это:

private void writePrivateJarVerifierField(boolean newValue) throws Exception {
    Class<?> clazz = Class.forName("java.util.jar.JarVerifier");
    Field field = clazz.getDeclaredField("parsingBlockOrSF");
    field.setAccessible(true);
    field.setBoolean(clazz.newInstance(), newValue);
}

Это дает мне Exception in thread "main" java.lang.InstantiationException: java.util.jar.JarVerifier

Я видел этот , этот , этот и этот вопрос уже, хотя я не могу получитьрешение моей проблемы.

Может кто-нибудь дать мне подсказку, пожалуйста?


Изменить 1: , так как я хочу изменить значение parsingBlockOrSF во время выполнения (как будто я изменил его через отладчик) Мне нужен существующий экземпляр JarVerifier, то есть JarFile (спасибо Gyro Gearless) Взглянув на подход, предложенный Ankur Chrungoo, я понял, что мне нужно получить уже существующий экземпляр JarVerifierтаким образом я попробовал это:

    private void writePrivateJarVerifierField(boolean newValue, JarFile jf) throws Exception {
    Class<?> clazz = Class.forName("java.util.jar.JarVerifier");
    Class<?> clacc = Class.forName("java.util.jar.JarFile");
    Field field = clazz.getDeclaredField("parsingBlockOrSF");
    Field field1 = clacc.getDeclaredField("jv");
    field.setAccessible(true);
    field1.setAccessible(true);
    field.setBoolean(field1.get(jf), newValue);
}

Где JarFile jf создает новый экземплярe JarVerifier и сохраняет его в переменной с именем jv.Вот почему я намереваюсь получить оба класса JarVerifier и JarFile, чтобы получить обе переменные, к которым я хочу получить доступ (одна из них является действительным логическим значением parsingBlockOrSF из JarVerifier, а другая - из экземпляра JarVerifier jv из экземпляра JarFile. На мой взгляд,приведенный выше код имеет смысл и должен работать, но это не так, так в чем же моя ошибка?

Исключение, которое я получаю: java.lang.NullPointerException at java.base/jdk.internal.reflect.UnsafeFieldAccessorImpl.ensureObj(UnsafeFieldAccessorImpl.java:57)


Редактировать 2: изменив последнюю строку кода выше на: field.setBoolean(field1.getType(), newValue);

Кажется, что объект распознан, хотя он Can not set boolean field java.util.jar.JarVerifier.parsingBlockOrSF to java.lang.Class


Редактировать 3: используя этот код:

    Class<?> clazz = Class.forName("java.util.jar.JarVerifier");
Class<?> clacc = Class.forName("java.util.jar.JarFile");
Field field = clazz.getDeclaredField("parsingBlockOrSF");
Field field1 = clacc.getDeclaredField("jv");
field.setAccessible(true);
field1.setAccessible(true);
field.setBoolean(clazz.getConstructor(byte[].class).newInstance(new byte[1]), newValue);

Я получаю эту ошибку: Exception in thread "main" java.lang.IllegalAccessException: class JarVerifier cannot access a member of class java.util.jar.JarVerifier (in module java.base) with modifiers "public"

Здесь я хочу изменить значение parsingBlockOrSF в jarVerifier внутри JarFile, поэтому ясначала должен работать с экземпляром jarFile, извлечь из него jarVerifier (что я пытаюсь сделать с field1 = calcc.getDeclaredField ("jv"), так как jarVerifier хранится в переменной jv внутри JarFile), а затем с помощью этогооbject, измените его свойство


Код, в котором создается JarFile:

    JarFile jf = null;
    jf = new JarFile(jarName, true);

jarName - это строка, представляющая путь к файлу .jar

Ответы [ 2 ]

0 голосов
/ 04 декабря 2018

Вы не можете изменить объект из пакета java.lang и java.util.jar.эти пакеты являются системными, и если вы не можете их изменить, они защищаются с помощью jvm.

0 голосов
/ 04 декабря 2018

Я мог видеть, что класс JarVerifier не имеет конструктора по умолчанию.Его конструктор выглядит примерно так: -

public JarVerifier(byte rawBytes[]) {
        manifestRawBytes = rawBytes;
        sigFileSigners = new Hashtable<>();
        verifiedSigners = new Hashtable<>();
        sigFileData = new Hashtable<>(11);
        pendingBlocks = new ArrayList<>();
        baos = new ByteArrayOutputStream();
        manifestDigests = new ArrayList<>();
    }

Итак, вам нужно получить конструктор не по умолчанию, используя отражение, а затем использовать его для создания экземпляра. Итак, ваш код должен выглядеть примерно так: -

field.setBoolean(clazz.getConstructor(byte[].class).newInstance(new byte[1]), newValue);

Ссылка на класс JarVerifier: https://github.com/netroby/jdk9-dev/blob/master/jdk/src/java.base/share/classes/java/util/jar/JarVerifier.java

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

Дополнительная ссылка: Java: newInstance класса, у которого нет конструктора по умолчанию

...