andras
andras

Reputation: 3655

How to set environment variable in Java without 'illegal reflective access'? How to use add-opens?

Long story short, I have to set an environment during runtime for a specific test.

The answers here on SO work fine, I am using this one. The problem is I am getting this warning:

WARNING: An illegal reflective access operation has occurred
WARNING: Illegal reflective access by **YOUR PACKAGE** (file: **YOUR FILE** ) to field java.util.Collections$UnmodifiableMap.m
WARNING: Please consider reporting this to the maintainers of **YOUR PACKAGE**
WARNING: Use --illegal-access=warn to enable warnings of further illegal reflective access operations
WARNING: All illegal access operations will be denied in a future release

I've started searching for a solution and the other SO answer here that 'solves' the problem with the unit tests uses the same method for setting the environment variable.

I am talking about this line of code from their Github source, which triggers this error. (field.setAccessible(true);)

So it looks like there is no other way to solve it, other than setting the given flag, just as the warning suggest.

Then I was wondering if this warning is severe at all and if my program is going to run at all in a couple months (I am using OpenJDK 11). It turns out this illegal-access setting will be removed in future release.

Source:

If you must continue to use a component that requires illegal access, then you can eliminate the warning messages by using one or more --add-opens options to open only those internal packages to which access is required.

Then later:

To verify that your application is ready for a future version of the JDK, run it with --illegal-access=deny along with any necessary --add-opens options.

Then I started to look for the syntax --add-opens needs and could not find how to use it properly.

I could find this, but I still don't understand how to use it in a Kotlin project and what the name of the modules are.

--add-opens module/package=target-module(,target-module)*/

Updates module to open package to target-module, regardless of module declaration.

How do use --add-opens to enable modification to java.util.Collections$UnmodifiableMap.m? Can I just enable add-opens to this only field or do I need to enable it to entire java.util.Collection? Is that reasonable?

Actually, I am only writing this entire question out like this, because there may be something wrong in the process that I am doing in a not-intended way.

Thanks for help anyone.

Upvotes: 5

Views: 2290

Answers (2)

Ashley Frieze
Ashley Frieze

Reputation: 5458

System Stubs v2.0.0 now provides a solution for this using Mockito.

https://github.com/webcompere/system-stubs

It can be used standalone:

new EnvironmentVariables("SET_THIS_VAR", "toThis")
   .execute(() -> runThisCode());

Or has a JUnit 5 plug in.

The EnvironmentVariableMocker in its core project could also be used stand-alone if required.

Upvotes: 0

aventurin
aventurin

Reputation: 2203

According to the syntax for --add-opens you've already cited above, you only could open modules on package level:

--add-opens module/package=target-module(,target-module)*

Since java.util.Collections belongs to the java.util package from the java.base module, you have to add the JVM argument

--add-opens java.base/java.util=target-module(,target-module)*

where your target modules must be the modules that want to access java.util.Collections$UnmodifiableMap.m, or ALL-UNNAMED modules.

--add-opens java.base/java.util=ALL-UNNAMED

Upvotes: 1

Related Questions