How to use sun.reflect package in jdk9/java-9?
Asked Answered
S

5

9

I am using jdk-9 and I want to use sun.reflect.* package in my code but I am getting the below exception

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

when I run below sample code using JDK-9

public static void main(String args[]){
   System.out.println(Reflection.getCallerClass(3));
}
Selfregard answered 24/1, 2017 at 4:41 Comment(0)
A
13

These sun.* packages were never part of the official API and not guaranteed to be present, even in JVMs before Java 9. Be prepared for them to vanish completely in the future, not even be recoverable via some options. Thankfully, there is an official API covering this functionality, eliminating the need for inofficial APIs.

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));
Ashburn answered 26/1, 2017 at 17:27 Comment(1)
This works post JDK10, upvoting for visibility as the correct answer.Raposa
L
7

Works fine with newer OpenJDK 9 EA builds. For example:

$ 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

Seems that it was fixed in 9-ea+115 build as a part of JDK-8137058. So probably you are using older EA build. In general @Holger is right: there are big chances that this API will disappear completely in future Java versions, so consider migrating to StackWalker API.

Leatri answered 12/2, 2017 at 11:51 Comment(2)
Indeed, sun.reflect.Reflection has moved to the jdk.unsupported module. So it will be there at least until Java 10.Inutility
@Inutility What about Java 11?Ellata
F
6

THIS ANSWER IS OUTDATED - CHECK THIS ONE INSTEAD!

A feature of the module system is that it allows library developers to strongly encapsulate implementation details due to the new accessibility rules. In a nutshell, most types in sun.* and com.sun.* packages will no longer be accessible. This is in line with Sun and later Oracle stating that these packages are not meant for public consumption.

A workaround is to export these packages at compile and launch time with a command line flag:

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

This exports the package sun.reflect from the module java.base to all modules including the unnamed module, which is the one that collects all classes on the class path.

Firewarden answered 24/1, 2017 at 9:52 Comment(0)
S
3
java -cp classes -XaddExports:java.base/sun.reflect Test

Jigsaw (java-9) has modularity concept in which they have designed java.base package for compact-1 and they have encapsulated sun.reflect.*. so sun.reflect.* can not be accessible outside. Due to that reason it giving the exception

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

Still to provide backward compatibility, they have provided the way to use that package like below.

java -cp classes -XaddExports:java.base/sun.reflect Test
Selfregard answered 24/1, 2017 at 4:41 Comment(2)
The answer is somewhat misleading: (1) compact profiles have nothing to do with it; (2) it fails for all kinds of other packages, too; (3) error message and proposed solution are outdated. See my answer instead.Firewarden
@Nicolai Your answer is outdated. See this answer instead :)Inutility
Z
0

Updating the thread with the latest release and changes brought in as mentioned in the Migration documentation as well. Appropriately correctly pointed out by @Holger already though.

The APIs in sun.reflect packages that remain accessible in JDK 9 are:

  • sun.reflect.Reflection::getCallerClass(int) Instead, use the stack-walking API, see JEP 259: Stack-Walking API.
  • sun.reflect.ReflectionFactory.newConstructorForSerialization

These APIs are accessible by default at run time. They have been moved to the jdk.unsupported module, which is present in the JRE and JDK images. Modules that need these APIs must declare a dependency upon the jdk.unsupported module.

The remaining internal APIs in the sun.misc and sun.reflect packages have been moved, since they should not be accessible. If you need to use one of these internal APIs, you can break encapsulation using the --add-exports command line option. (similar to as answered by @NIrav). Though as suggested in the docs, this option should only be used as a temporary aid to migration.

Zing answered 5/9, 2017 at 6:6 Comment(1)
If you are new to java9 modules, it would be useful to know that you have to add a new file into your package, called module-info.java, that declares the dependency on jdk.unsupported. it looks like this: module com.mypackage { requires jdk.unsupported; requires org.apache.logging.log4j; exports com.mypackage; } Cargill

© 2022 - 2024 — McMap. All rights reserved.