如何在jdk9 / java-9中使用sun.reflect包?

时间:2017-01-24 04:41:28

标签: java java-9 jigsaw

我正在使用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));
}

5 个答案:

答案 0 :(得分:7)

适用于较新的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

似乎它已作为JDK-8137058的一部分在9-ea + 115版本中修复。所以你可能正在使用旧的EA版本。一般来说,@ Holger是对的:这个API很有可能在将来的Java版本中完全消失,所以请考虑迁移到StackWalker API。

答案 1 :(得分:5)

这个答案已经过时 - 检查THIS ONE INSTEAD!

模块系统的一个特性是它允许库开发人员强烈封装由于新accessibility rules而导致的实现细节。简而言之,sun.*com.sun.*包中的大多数类型将无法再访问。这与Sun和后来的Oracle一致,声称这些软件包不适合公共消费。

解决方法是使用命令行标志在编译和启动时导出这些包:

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

这会将软件包sun.reflect从模块 java.base 导出到所有模块,包括unnamed module,这是收集类路径上所有类的模块。 / p>

答案 2 :(得分:5)

这些sun.*软件包从来都不是官方API的一部分,并且不能保证存在,即使在Java 9之前的JVM中也是如此。为将来完全消失做好准备,甚至不能通过某些选项恢复。值得庆幸的是,有一个官方API涵盖了这个功能,消除了对非官方API的需求。

获取直接调用者类
Class<?> c = StackWalker.getInstance(StackWalker.Option.RETAIN_CLASS_REFERENCE)
                        .getCallerClass();
获取堆栈中的第n个调用者(例如,第三个,如您的示例中所示):
Class<?> c = StackWalker.getInstance(StackWalker.Option.RETAIN_CLASS_REFERENCE).walk(s ->
     s.map(StackWalker.StackFrame::getDeclaringClass).skip(3).findFirst().orElse(null));

答案 3 :(得分:3)

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

Jigsaw(java-9)具有模块化概念,他们为compact-1设计了java.base包,它们封装了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

答案 4 :(得分:0)

使用最新版本更新线程,并更新Migration documentation中提到的更改。已经恰当地正确地pointed out by @Holger了。

JDK 9中仍可访问的sun.reflect包中的API包括:

  
      
  • sun.reflect.Reflection::getCallerClass(int)相反,请使用   stack-walking API,请参阅JEP 259: Stack-Walking API.
  •   
  • sun.reflect.ReflectionFactory.newConstructorForSerialization
  •   

默认情况下,这些API在运行时可访问。它们已移至jdk.unsupported模块,该模块存在于JRE和JDK映像中。需要这些API的模块必须声明对jdk.unsupported模块的依赖。

sun.misc和sun.reflect包中的其余内部API 已被移动,因为它们不应该被访问。如果需要使用其中一个内部API,可以使用--add-exports命令行选项中断封装。 (类似于answered by @NIrav)。 尽管如文档中所述,此选项仅应用作迁移的临时辅助工具。