Как запустить код на jre9, который был скомпилирован с jdk8 и использовать Unsafe
У меня есть код, который был скомпилирован с jdk8 в качестве цели и источника для Java 1.8 и использую Unsafe. Я попытался запустить эту программу с jdk9, но она не работает со следующим исключением:
java.lang.NoSuchMethodError: sun.misc.Unsafe.getByte
Пакет sun.misc.Unsafe не удаляется из jdk9, поэтому я ожидал запуска кода. Я не могу перекомпилировать код с jdk9, я ожидал, что Java должен быть обратно совместимым.
Я создаю небольшой тест, который не работает для меня. Тестовый класс:
import java.lang.reflect.Field;
import sun.misc.Unsafe;
public class Test {
public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException {
System.out.println("before");
Field theUnsafeField = Unsafe.class.getDeclaredField("theUnsafe");
theUnsafeField.setAccessible(true);
Unsafe unsafe = (Unsafe) theUnsafeField.get(null);
unsafe.getByte(new Object(), 4);
System.out.println("after");
}
}
Затем я компилирую код с помощью jdk8.
C:\Java-IDE\jdk1.8.0_121\bin\javac.exe Test.java
Тогда, если я запускаю его с jdk8, он работает:
C:\Java-IDE\jdk1.8.0_121\bin\java.exe Test
before
after
Если я запускаю его с jdk9, он выдает исключение:
C:\Java-IDE\jdk-9.0.4_windows-x64_bin\bin\java.exe Test
before
Exception in thread "main" java.lang.NoSuchMethodError: sun.misc.Unsafe.getByte(Ljava/lang/Object;I)B
at Test.main(Test.java:13)
Я считаю, что это должно быть также возможно запустить его под JDK9. Является ли это возможным?
2 ответа
Метод byte Unsafe.getByte(Object, int)
был удален в Java 9, но перекомпиляция устраняет проблему, так как это вызовет вызов byte Unsafe.getByte(Object, long)
то, что действительно является предполагаемой заменой.
Обратите внимание, что даже помимо того факта, что Unsafe
является неофициальным, неподдерживаемым API, который не должен использоваться приложениями, использующими методы int
смещения устарели в пользу методов, использующих long
поскольку 1.4.1
Это означает, что для адаптации старого кода было полтора десятилетия, но ваше утверждение о том, что код "был скомпилирован с jdk8 в качестве цели", указывает на то, что он на самом деле даже моложе этого.
Учитывая тот факт, что планируется полное удаление sun.misc.Unsafe
было объявлено несколько раз, и изменить код не удастся, если он будет работать в будущих версиях JVM. Если вы не можете перекомпилировать его, спросите себя, как должно выглядеть будущее обслуживание кода, который вы не можете перекомпилировать. Если код должен быть заморожен, заморозьте и версию JVM. В противном случае вам нужно найти способ перекомпилировать или заменить его.
Да, Java обратно совместим, но это для API Java. Пакет sun.misc - это один из пакетов, которые Sun/Oracle объявил перемещаемыми / обновляемыми / удаляемыми без предварительного предупреждения.
Значит это было
Чтобы ответить на ваш вопрос, вам необходимо обновить код
РЕДАКТИРОВАТЬ:
Как сказал Алан Бейтман в своем комментарии, очевидным решением будет перекомпилировать
Но если вы не можете и если вы не против уродливых хаков, вы можете:
получите источник sun.misc.Unsafe и вставьте необходимые / отсутствующие методы
создайте пользовательский загрузчик классов, который, по сути, будет делать то же самое, что и системный загрузчик классов, но при запросе на загрузку sun.misc.Unsafe вместо этого загрузит вашу версию Unsafe.
Запустите ваше приложение с вашим пользовательским загрузчиком классов
java -Djava.system.class.loader=com.xxx.MyCustomClassLoader xxx
Некрасиво но может работать без перекомпиляции