Как использовать пакет sun.reflect в jdk9/java-9?

Я использую jdk-9 и хочу использовать пакет sun.reflect.* в своем коде, но получаю следующее исключение

Exception in thread 'main' java.lang.IllegalAccessError : class Test (in moudle: Unnamed Module) cannot access class sun.reflect.Reflaction (in module:java.base), sun.reflect is not exported to Unnamed module

когда я запускаю пример кода ниже, используя JDK-9

public static void main(String args[]){
   System.out.println(Reflection.getCallerClass(3));
}

person NIrav Modi    schedule 24.01.2017    source источник


Ответы (5)


Эти sun.* пакеты никогда не входили в официальный API, и их наличие не гарантируется даже в JVM до Java 9. Будьте готовы к тому, что в будущем они полностью исчезнут, и их даже нельзя будет восстановить с помощью некоторых опций. К счастью, существует официальный API, охватывающий эту функциональность, что устраняет необходимость в неофициальных API.

Get the immediate caller class
Class<?> c = StackWalker.getInstance(StackWalker.Option.RETAIN_CLASS_REFERENCE)
                        .getCallerClass();
Get the n’th caller on the stack (e.g. third, like in your example):
Class<?> c = StackWalker.getInstance(StackWalker.Option.RETAIN_CLASS_REFERENCE).walk(s ->
     s.map(StackWalker.StackFrame::getDeclaringClass).skip(3).findFirst().orElse(null));
person Holger    schedule 26.01.2017
comment
Это работает после JDK10, голосуя за видимость как правильный ответ. - person Amr Gawish; 27.11.2018

Отлично работает с более новыми сборками OpenJDK 9 EA. Например:

$ java -version
java version "9-ea"
Java(TM) SE Runtime Environment (build 9-ea+138)
Java HotSpot(TM) 64-Bit Server VM (build 9-ea+138, mixed mode)

$ javac Test.java
Test.java:5: warning: Reflection is internal proprietary API and may be removed in a future release
    System.out.println(Reflection.getCallerClass(3));
                       ^
Note: Test.java uses or overrides a deprecated API.
Note: Recompile with -Xlint:deprecation for details.
1 warning

$ java Test
null

Кажется, это было исправлено в сборке 9-ea+115 как часть JDK-8137058. Так что, вероятно, вы используете более старую сборку EA. В целом @Holger прав: есть большие шансы, что этот API полностью исчезнет в будущих версиях Java, поэтому подумайте о переходе на API StackWalker.

person Tagir Valeev    schedule 12.02.2017
comment
Действительно, sun.reflect.Reflection переместился в модуль jdk.unsupported. Так что он будет там как минимум до Java 10. - person ZhekaKozlov; 18.05.2017

ЭТОТ ОТВЕТ УСТАРЕЛ - ПРОВЕРЬТЕ ЭТО ВМЕСТО!

Особенностью модульной системы является то, что она позволяет разработчикам библиотек строго инкапсулировать детали реализации благодаря новому правила доступа. Короче говоря, большинство типов в пакетах sun.* и com.sun.* больше не будут доступны. Это соответствует заявлениям Sun и более поздних версий Oracle о том, что эти пакеты не предназначены для публичного использования.

Обходной путь — экспортировать эти пакеты во время компиляции и запуска с флагом командной строки:

--add-exports java.base/sun.reflect=ALL-UNNAMED

Это экспортирует пакет sun.reflect из модуля java.base во все модули, включая безымянный модуль, который собирает все классы на пути к классам.

person Nicolai Parlog    schedule 24.01.2017

java -cp classes -XaddExports:java.base/sun.reflect Test

Jigsaw (java-9) имеет концепцию модульности, в которой они разработали пакет java.base для compact-1 и инкапсулировали sun.reflect.*. поэтому sun.reflect.* не может быть доступен снаружи. По этой причине он дает исключение

Exception in thread 'main' java.lang.IllegalAccessError : class Test (in moudle: Unnamed Module) cannot access class sun.reflect.Reflaction (in module:java.base), sun.reflect is not exported to Unnamed module

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

java -cp classes -XaddExports:java.base/sun.reflect Test
person NIrav Modi    schedule 24.01.2017
comment
Ответ несколько вводит в заблуждение: (1) компактные профили тут ни при чем; (2) это также не работает для всех видов других пакетов; (3) сообщение об ошибке и предлагаемое решение устарели. Вместо этого см. мой ответ. - person Nicolai Parlog; 24.01.2017
comment
@ Николай Ваш ответ устарел. Вместо этого см. этот ответ :) - person ZhekaKozlov; 18.05.2017

Обновление потока с последним выпуском и внесенными изменениями, как указано в Документация по миграции. Тем не менее, правильно указано @Holger.

API в пакетах sun.reflect, которые остаются доступными в JDK 9:

  • sun.reflect.Reflection::getCallerClass(int) Вместо этого используйте API обхода стека, см. JEP 259: API обхода стека.
  • sun.reflect.ReflectionFactory.newConstructorForSerialization

Эти API доступны по умолчанию во время выполнения. Они были перемещены в модуль jdk.unsupported, который присутствует в образах JRE и JDK. Модули, которым нужны эти API, должны объявить зависимость от модуля jdk.unsupported.

Остальные внутренние API в пакетах sun.misc и sun.reflect были перемещены, так как они не должны быть доступны. Если вам нужно использовать один из этих внутренних API, вы можете разорвать инкапсуляцию с помощью параметра командной строки --add-exports. (аналогично ответу @NIrav). Хотя, как предлагается в документации, эту опцию следует использовать только как временную помощь при миграции.

person Naman    schedule 05.09.2017
comment
Если вы новичок в модулях java9, было бы полезно знать, что вы должны добавить в свой пакет новый файл с именем module-info.java, который объявляет зависимость от jdk.unsupported. выглядит так: module com.mypackage { requires jdk.unsupported; requires org.apache.logging.log4j; exports com.mypackage; } - person Bretton Wade; 09.12.2017