Попытка изменить значение свойства во время выполнения, используя результаты отражения в NullPointerException - PullRequest
1 голос
/ 19 сентября 2019

У меня есть класс, для которого я пишу юнит-тесты:

import java.io.File;

public class MyLogger {

    private final File logFile = new File("default");

    public File getLogFile() {
        return this.logFile;
    }
}

Я хотел бы изменить значение, присвоенное logFile, из другого класса, например:

import java.io.File;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;

public class Main {

    public static void main(String[] args) throws NoSuchFieldException, SecurityException, Exception {

        MyLogger logger = new MyLogger();
        System.out.println(logger.getLogFile());

        setFinal(MyLogger.class.getDeclaredField("logFile"), new File("changed"));
        System.out.println(logger.getLogFile());
    }

    private static void setFinal(Field field, Object newValue) throws Exception {
        field.setAccessible(true);

        Field modifiersField = Field.class.getDeclaredField("modifiers");
        modifiersField.setAccessible(true);
        modifiersField.setInt(field, field.getModifiers() & ~Modifier.FINAL);

        field.set(null, newValue);
    }
}

Но я получаю вывод / исключение ниже:

default
Exception in thread "main" java.lang.NullPointerException
    at sun.reflect.UnsafeFieldAccessorImpl.ensureObj(UnsafeFieldAccessorImpl.java:57)
    at sun.reflect.UnsafeObjectFieldAccessorImpl.set(UnsafeObjectFieldAccessorImpl.java:75)
    at java.lang.reflect.Field.set(Field.java:764)
    at Main.setFinal(Main.java:23)
    at Main.main(Main.java:12)

Ответы [ 3 ]

1 голос
/ 19 сентября 2019

Вы используете метод Field.set неправильно.Вам нужно предоставить объект , для которого должно быть установлено новое значение поля, в вашем коде это должен быть объект logger, но вы передаете null:

public static void main(String[] args) throws NoSuchFieldException, SecurityException, Exception {

    MyLogger logger = new MyLogger();
    System.out.println(logger.getLogFile());

    setFinal(logger, MyLogger.class.getDeclaredField("logFile"), new File("changed"));
    System.out.println(logger.getLogFile());
}

private static void setFinal(MyLogger logger, Field field, Object newValue) throws Exception {
    field.setAccessible(true);

    Field modifiersField = Field.class.getDeclaredField("modifiers");
    modifiersField.setAccessible(true);
    modifiersField.setInt(field, field.getModifiers() & ~Modifier.FINAL);

    field.set(logger, newValue);
}

Это согласно сигнатуре метода Field.set из документов :

Устанавливает поле, представленное этим объектом поля, в указанном аргументе объектав указанное новое значение.

1 голос
/ 19 сентября 2019

Проблема с первым аргументом метода set.Он ожидает экземпляр объекта, который вы пытаетесь изменить, чтобы выполнить изменение.Прямо сейчас, то, что вы делаете, похоже на попытку выполнить null.logFile = newValue, что, очевидно, завершится неудачей.

Вам необходимо добавить еще один аргумент в ваш метод setFinal и передать переменную logger виспользовать в качестве этого параметра.

public static void main(String[] args) throws NoSuchFieldException, SecurityException, Exception {

  MyLogger logger = new MyLogger();
  System.out.println(logger.getLogFile());

  setFinal(MyLogger.class.getDeclaredField("logFile"), logger, new File("changed"));
  System.out.println(logger.getLogFile());
}

private static void setFinal(Field field, Object toModify, Object newValue) throws Exception {
  field.setAccessible(true);

  Field modifiersField = Field.class.getDeclaredField("modifiers");
  modifiersField.setAccessible(true);
  modifiersField.setInt(field, field.getModifiers() & ~Modifier.FINAL);

  field.set(toModify, newValue);
}
0 голосов
/ 19 сентября 2019

Я могу сделать это, используя java.lang.reflect.Method, чтобы проверить приведенный ниже код, помогает ли это решить вашу проблему.

Method method = MyLogger.getClass().getDeclaredMethod("getLogFile");
            method.setAccessible(true);

в getDeclaredMethod необходимо указать полное имя метода.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...