Reputation: 51160
This exception occurs in a wide variety of scenarios when running an application on Java 9. Certain libraries and frameworks (Spring, Hibernate, JAXB) are particularly prone to it. Here's an example from Javassist:
java.lang.reflect.InaccessibleObjectException: Unable to make protected final java.lang.Class java.lang.ClassLoader.defineClass(java.lang.String,byte[],int,int,java.security.ProtectionDomain) throws java.lang.ClassFormatError accessible: module java.base does not "opens java.lang" to unnamed module @1941a8ff
at java.base/jdk.internal.reflect.Reflection.throwInaccessibleObjectException(Reflection.java:427)
at java.base/java.lang.reflect.AccessibleObject.checkCanSetAccessible(AccessibleObject.java:201)
at java.base/java.lang.reflect.Method.checkCanSetAccessible(Method.java:192)
at java.base/java.lang.reflect.Method.setAccessible(Method.java:186)
at javassist.util.proxy.SecurityActions.setAccessible(SecurityActions.java:102)
at javassist.util.proxy.FactoryHelper.toClass2(FactoryHelper.java:180)
at javassist.util.proxy.FactoryHelper.toClass(FactoryHelper.java:163)
at javassist.util.proxy.ProxyFactory.createClass3(ProxyFactory.java:501)
at javassist.util.proxy.ProxyFactory.createClass2(ProxyFactory.java:486)
at javassist.util.proxy.ProxyFactory.createClass1(ProxyFactory.java:422)
at javassist.util.proxy.ProxyFactory.createClass(ProxyFactory.java:394)
The message says:
Unable to make protected final java.lang.Class java.lang.ClassLoader.defineClass(java.lang.String,byte[],int,int,java.security.ProtectionDomain) throws java.lang.ClassFormatError accessible: module java.base does not "opens java.lang" to unnamed module @1941a8ff
What can be done to avoid the exception and have the program run successfully?
Upvotes: 239
Views: 330431
Reputation: 3421
If the issue is with the tomcat running as a Windows Service, following can be done:
Go to Start > Programs > Apache Tomcat > Configure Tomcat (Run as administrator)
In Windows 11, type Configure Tomcat on search, then select Run as administrator Following window will be displayed(mine is Tomcat 9)
Then select the Java tab and go to Java 9 Options
Add the required lines to list of options. For me added following two:
--add-opens=java.base/java.util=ALL-UNNAMED
--add-opens=java.base/java.util.concurrent=ALL-UNNAMED
The resulted screen will be similar to following:
Click Apply
and Ok
, then restart the Tomcat service from System services list or from Task Manager.
Upvotes: 1
Reputation: 5097
I was having the same issue deploying my Spring Boot application to aws ecs
. Instead of modifying the pom.xml
the argument --add-opens=java.base/java.lang=ALL-UNNAMED
must be added as an enviroment variable to the container.
Hope it helps somebody else.
Upvotes: 0
Reputation: 1
If you encountered this in maven project try add open before module name in module-info.java
open module org.application {...}
it worked for me
Upvotes: -1
Reputation: 5459
Using --add-opens
should be considered a workaround.
The right thing is for Spring, Hibernate, and other libraries performing illegal access to fix their issues.
Upvotes: 12
Reputation: 486
I used above suggestion for --add-opens
in my environment, but at the time of building the code in a pipeline the problem was happening once again. It's important to mention I was using Maven (cucumber as well), and I was leveraging the spring-boot-maven-plugin
, in the end the following configuration allowed the pipeline build
execution:
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<executions>
<execution>
<id>pre-integration-test</id>
<goals>
<goal>start</goal>
</goals>
<configuration>
<environmentVariables>
<JDK_JAVA_OPTIONS>--add-opens java.base/java.math=ALL-UNNAMED</JDK_JAVA_OPTIONS>
</environmentVariables>
</configuration>
</execution>
</executions>
</plugin>
Env details:
Upvotes: 1
Reputation: 193
I was getting LinkedHashMap.accessOrder not accessible in java 11 reflection. Tried many things, the only solution that worked is to put this in the servlet class:
static {
try {
Field field = LinkedHashMap_CustomFieldSerializer.class.getDeclaredField("reflectionHasFailed");
field.setAccessible(true);
((AtomicBoolean)field.get(null)).set(true);
} catch (NoSuchFieldException | SecurityException | IllegalArgumentException | IllegalAccessException e) {
throw new RuntimeException(e);
}
}
Upvotes: 0
Reputation: 1386
NOTE: only for legacy situations, do not use in any other case.
I bumped into this problem during testing. I'm using shazamcrest in combination with jMock. This is very handy but shazamcrest is using gson which in turn uses some approach to compare objects that cases this error.
I added the earlier already suggestion solution to my Maven pom.xml in the surefire plugin configuration like this:
<configuration>
<!-- The add-opens are for shazamcrest that uses gson for random classes -->
<argLine>
--add-opens java.base/java.time=ALL-UNNAMED
--add-opens java.base/java.math=ALL-UNNAMED
--add-opens java.base/java.lang=ALL-UNNAMED
--add-opens java.base/java.lang.reflect=ALL-UNNAMED
</argLine>
</configuration>
This solved the problem.
The only problem left was that running these tests inside Eclipse still poses a challenge. For this I had the add the same settings in the "Run configuration" in the JVM arguments.
Upvotes: 0
Reputation: 1
exporting the java version solved this issue for me
export JAVA_HOME=$(/usr/libexec/java_home -v 1.8)
export JAVA_HOME=$(/usr/libexec/java_home -v 11.0.11)
Upvotes: -2
Reputation: 543
you can use Unsafe
to bypass, for example
import sun.misc.Unsafe;
import java.lang.reflect.Field;
class Scratch {
private static Unsafe reflectGetUnsafe() {
try {
Field field = Unsafe.class.getDeclaredField("theUnsafe");
field.setAccessible(true);
return (Unsafe) field.get(null);
} catch (Exception e) {
return null;
}
}
public static void main (String[]args) throws Exception {
Class<?> clazz = Class.forName("java.lang.ApplicationShutdownHooks");
Field field = clazz.getDeclaredField("hooks");
// this method can not be used in Java 9+ with java modules
// Unable to make field private static java.util.IdentityHashMap java.lang.ApplicationShutdownHooks.hooks accessible: module java.base does not "opens java.lang" to unnamed module @452b3a41
// field.setAccessible(true);
Unsafe safe = reflectGetUnsafe();
Object m = safe.getObject(clazz, safe.staticFieldOffset(field));
System.out.println(m.getClass().toString());
}
}
Reference: https://xz.aliyun.com/t/10075
Upvotes: -1
Reputation: 2140
After Java modularization, some jdk internal classes cannot be accessed, so they will report errors directly. So, you need to add below option in VM config when executing the Java program:
For Intellij users follow steps: edit run/debug configuration -> add the below option in VM options:
--add-opens java.base/java.lang=ALL-UNNAMED
This link might be helpful: upgrading to Java 17
Upvotes: 12
Reputation: 579
It is still possible to try with older JKD version.
For Eclipse you need to do 2 things. Go to
Window -> Preference -> java -> Compiler Set Compiler Compliance Level to Specific version In my case, Eclipse version was set to JDK 16 I reverted it to 1.8 as my code was written in 1.8
Window -> Preferences -> Java -> Installed JREs. Add the JRE installation path (Select Standard VM)
It worked smoothly for me..
Upvotes: 27
Reputation: 119
Add to your JVM command line or go to eclipse.ini
file in Eclipse Directory and add the following:
--add-opens java.base/java.lang=ALL-UNNAMED
Pre Java 17 (because Java 17 removed this parameter) you would also add:
--illegal-access=warn
Upvotes: 7
Reputation: 21
I spent a lot of time today trying to get around adding the --add-opens JVM option. Upgrading to SpringBoot 2.6.4 (which if you're using dependency management, will upgrade to spring framework 5.3.16) fixed the issue without adding the JVM option.
https://stackoverflow.com/a/71330846/14396065
Upvotes: 1
Reputation: 148
In 2021, the issue only appeared when I used OpenJDK language version 16. It worked when I downgraded to a lower version. I am guessing this is because OpenJDK made this: JEP 396: Strongly Encapsulate JDK Internals by Default
Upvotes: 3
Reputation: 9
In eclipse:
Windows -> Preferences -> Java -> Installed JREs
In the wizard that open click on Add, select Standard VM
and click Next
, and then Browse to the path of your installed Java in program files. Eg, for me it was C:\Program Files\Java\jre1.8.0_301\lib
.
Click on Finish then select the newly added JR.
Right-click on your Project -> Build Path -> Configure Build Path
In the wizard that opens go to the Libraries
tab and click on Add Library
then select JRE System Library
click next. Select Alternate JRE
and then select the JRE your added earlier from the drop down. Click on Finish.
Go to the Order and Export
tab and select your added JRE and move it above the other System library that was causing the problem. Select apply and close. You're done.
Upvotes: 0
Reputation: 19173
Just a recent feedback
Many proposals to solve this issue have to do with the vm launcher option --illegal-access
.
According to Oracle, with JEP 403 (link1) and JEP 403 (link2) which has been decided to be delivered from JDK 17 and onwards , the launcher option --illegal-access
will stop working!
Summary Strongly encapsulate all internal elements of the JDK, except for critical internal APIs such as sun.misc.Unsafe. It will no longer be possible to relax the strong encapsulation of internal elements via a single command-line option, as was possible in JDK 9 through JDK 16.
And
With this change, it will no longer be possible for end users to use the --illegal-access option to enable access to internal elements of the JDK. (A list of the packages affected is available here.) The sun.misc and sun.reflect packages will still be exported by the jdk.unsupported module, and will still be open so that code can access their non-public elements via reflection. No other JDK packages will be open in this way.
It will still be possible to use the --add-opens command-line option, or the Add-Opens JAR-file manifest attribute, to open specific packages.
So the following solution will keep working
# --add-opens has the following syntax: {A}/{package}={B}
java --add-opens java.base/java.lang=ALL-UNNAMED
But the solution with --illegal-access
will stop working from JDK 17
and onwards.
Upvotes: 41
Reputation: 21
I was facing similar issue while running SornarQube and I got the workaround to upload the sonar report by doing following:
Existing package: Java 16.0.2, MacOS (BigSur)
Hope this will help to someone if facing the same issue, s/he can try for this. :-)
Upvotes: 2
Reputation: 21
Faced the same issue. One of the Reason might be using wrong JDK / Project SDK.
To Resolve this issue in Intellij:
Right Click on the Maven Project -> Open Module Settings -> Project Settings -> Project -> Select your SDK to already installed JDK 1.8
It worked for me !
Upvotes: 0
Reputation: 337
For me i just changed spring-boot-starter-web version and worked for me
Upvotes: -1
Reputation: 71
I faced the same issue after importing an existing Springboot project based on JDK1.8 into SpringTestSuite4. When I started the application on an embedded Tomcat server, I got this error
java.lang.reflect.InaccessibleObjectException: Unable to make protected final java.lang.Class java.lang.ClassLoader.defineClass(java.lang.String,byte[],int,int,java.security.ProtectionDomain) throws java.lang.ClassFormatError accessible: module java.base does not "opens java.lang" to unnamed module @140c9f39 %09
I added the pre-installed JDK1.8 JRE from my PC to SpringTestSuite4 in the Installed JRE section under Window -> Preferences -> Java and made the added JRE the default. Then I clicked on Apply and then Close.
It worked for me.
Upvotes: 1
Reputation: 11
How to tell eclipse to add-exports when compiling
I followed the steps from the top comment but in Add-exports configuration
pop-up window, I input the modules that were in my error and selected opens
checkbox instead of exports
checkbox and saved it. This fixed my problem.
Upvotes: 0
Reputation: 63
I had the same issue in 2021 while using openJDK 1.8 and STS 4.
Window => Preferences => Java => Installed JREs.
I added a new JRE (mentioned below) using the add option , browsed to the openJdk folder, select OK. Make the new JDK default. Click on apply and close.
/usr/lib/jvm/java-1.8.0-openjdk-amd64/jre
It worked like a charm:)
Upvotes: 5
Reputation: 331
Add --illegal-access=warn and --add-opens java.base/java.lang=ALL-UNNAMED to your eclipse.ini
Upvotes: 7
Reputation: 51160
The exception is caused by the Java Platform Module System that was introduced in Java 9, particularly its implementation of strong encapsulation. It only allows access under certain conditions, the most prominent ones are:
The same limitations are true for reflection, which the code causing the exception tried to use.
More precisely the exception is caused by a call to setAccessible
.
This can be seen in the stack trace above, where the corresponding lines in javassist.util.proxy.SecurityActions
look as follows:
static void setAccessible(final AccessibleObject ao,
final boolean accessible) {
if (System.getSecurityManager() == null)
ao.setAccessible(accessible); // <~ Dragons
else {
AccessController.doPrivileged(new PrivilegedAction() {
public Object run() {
ao.setAccessible(accessible); // <~ moar Dragons
return null;
}
});
}
}
To make sure the program runs successfully the module system must be convinced to allow access to the element on which setAccessible
was called.
All information required for that is contained in the exception message but there are a number of mechanisms to achieve this.
Which is the best one depends on the exact scenario that caused it.
Unable to make {member} accessible: module {A} does not 'opens {package}' to {B}
By far the most prominent scenarios are the following two:
A library or framework uses reflection to call into a JDK module. In this scenario:
{A}
is a Java module (prefixed with java.
or jdk.
){member}
and {package}
are parts of the Java API{B}
is a library, framework, or application module; often unnamed module @...
A reflection-based library/framework like Spring, Hibernate, JAXB, ... reflects over application code to access beans, entities,... In this scenario:
{A}
is an application module{member}
and {package}
are part of the application code{B}
is either a framework module or unnamed module @...
Note that some libraries (JAXB, for example) can fail on both accounts so have a close look at what scenario you're in! The one in the question is case 1.
The JDK modules are immutable for application developers so we can not change their properties. This leaves only one possible solution: command line flags. With them it is possible to open specific packages up for reflection.
So in a case like above (shortened)...
Unable to make java.lang.ClassLoader.defineClass accessible: module java.base does not "opens java.lang" to unnamed module @1941a8ff
... the correct fix is to launch the JVM as follows:
# --add-opens has the following syntax: {A}/{package}={B}
java --add-opens java.base/java.lang=ALL-UNNAMED
If the reflecting code is in a named module, ALL-UNNAMED
can be replaced by its name.
Note that it can sometimes be hard to find a way to apply this flag to the JVM that will actually execute the reflecting code. This can be particularly tough if the code in question is part of the project's build process and is executed in a JVM that the build tool spawned.
If there are too many flags to be added, you might consider using the encapsulation kill switch --permit-illegal-access
instead. It will allow all code on the class path to reflect overall named modules. Note that this flag will only work in Java 9!
In this scenario, it is likely that you can edit the module that reflection is used to break into.
(If not, you're effectively in case 1.) That means that command-line flags are not necessary and instead module {A}
's descriptor can be used to open up its internals.
There are a variety of choices:
exports {package}
, which makes it available at compile and run time to all codeexports {package} to {B}
, which makes it available at compile and run time but only to {B}
opens {package}
, which makes it available at run time (with or without reflection) to all codeopens {package} to {B}
, which makes it available at run time (with or without reflection) but only to {B}
open module {A} { ... }
, which makes all its packages available at run time (with or without reflection) to all codeSee this post for a more detailed discussion and comparison of these approaches.
Upvotes: 322
Reputation: 31
I had warnings with hibernate 5.
Illegal reflective access by javassist.util.proxy.SecurityActions
I added latest javassist library to dependencies gradle:
compile group: 'org.javassist', name: 'javassist', version: '3.22.0-GA'
This solved my problem.
Upvotes: 3
Reputation: 415
This is a very challenging problem to solve; and as noted by others, the --add-opens option is only a workaround. The urgency to resolve the underlying issues will only grow once Java 9 becomes publicly available.
I found myself on this page after receiving this exact Javassist error while testing my Hibernate-based application on Java 9. And since I aim to support Java 7, 8, and 9 on multiple platforms, I struggled to find the best solution. (Note that Java 7 and 8 JVMs will abort immediately when they see an unrecognized "--add-opens" argument on the command line; so this can't be solved with static changes to batch files, scripts, or shortcuts.)
It would be nice to receive official guidance from the authors of mainstream libraries (such as Spring and Hibernate), but with 100 days to go until the currently projected release of Java 9, that advice still seems hard to find.
After much experimentation and testing, I was relieved to find a solution for Hibernate:
This avoids the need for Hibernate to perform Javassist-based class modifications at runtime, eliminating the stack trace shown in the original post.
HOWEVER, you should thoroughly test your application afterward. The bytecode changes applied by Hibernate at build-time appear to differ from the ones applied at runtime, causing slightly different application behavior. Unit tests in my app that have succeeded for years suddenly failed when I enabled build-time bytecode enhancement. (I had to chase down new LazyInitializationExceptions and other problems.) And the behavior seems to vary from one version of Hibernate to another. Proceed with caution.
Upvotes: 7