Помимо перекомпиляции rt.jar
есть ли способ заменить вызов currentTimeMillis()
одним из моих?
1 # Правильный способ сделать это - использовать объект Clock
и абстрактное время.
Я знаю это, но мы будем запускать код, разработанный бесконечным числом разработчиков, которые не реализовали Clock
, или сделали свою собственную реализацию.
2 # Используйте макет, например JMockit, чтобы издеваться над этим классом.
Даже если это работает только с Hotspot disabled -Xint
, и у нас есть успех, используя приведенный ниже код, он не "сохраняется" в внешних библиотеках. Это означает, что вам придется обманывать его повсюду, что, поскольку код находится вне нашего контроля, не представляется возможным. Весь код под main()
возвращает 0 milis (как из примера), но new DateTime()
вернет фактические системные миллионы.
@MockClass(realClass = System.class)
public class SystemMock extends MockUp<System> {
// returns 1970-01-01
@Mock public static long currentTimeMillis() { return 0; }
}
3 # Повторно объявить System
при запуске с помощью -Xbootclasspath/p
(отредактировано)
Хотя возможно, и хотя вы можете создавать/изменять методы, тот, о котором идет речь, объявляется как public static native long currentTimeMillis();
. Вы не можете изменить его декларацию, не врываясь в собственный запатентованный и собственный код Sun, что сделало бы это упражнение обратной инженерии и вряд ли устойчивым.
Все последние аварии SUN JVM со следующей ошибкой:
EXCEPTION_ACCESS_VIOLATION (0xc0000005) at pc=0x00000, pid=4668, tid=5736
4 # Использовать собственный класс ClassLoader (новый тест, предложенный в комментариях)
В то время как тривиально заменить систему CL с помощью -Djava.system.class.loader
JVM фактически загружает пользовательский классLoader, прибегая к классу classLoader по умолчанию, и система даже не толкается через пользовательский CL.
public class SimpleClassLoader extends ClassLoader {
public SimpleClassLoader(ClassLoader classLoader) {
super(classLoader);
}
@Override
public Class<?> loadClass(String name) throws ClassNotFoundException {
return super.loadClass(name);
}
}
Мы видим, что java.lang.System
загружается из rt.jar
с помощью java -verbose:class
Line 15: [Loaded java.lang.System from C:\jdk1.7.0_25\jre\lib\rt.jar]
У меня заканчиваются варианты.
Есть ли какой-то подход, который мне не хватает?