What is an illegal reflective access?
Asked Answered
I

4

245

There are a lot of questions about illegal reflective access in Java 9.

I have found plenty of discussion about working around the error messages, but I would love to know what an illegal reflective access actually is.

So my question is:

What defines an illegal reflective access and what circumstances trigger the warning?

I have gathered that it has something to do with the encapsulation principles that were introduced in Java 9, but I can't find an explanation of how it all hangs together, what triggers the warning, and in what scenario.

Intoxicant answered 9/5, 2018 at 11:1 Comment(1)
this may interest you as well: jaxenter.com/jdk-9-replace-permit-illegal-access-134180.htmlBuddie
T
90

Apart from an understanding of the accesses amongst modules and their respective packages. I believe the crux of it lies in the Module System#Relaxed-strong-encapsulation and I would just cherry-pick the relevant parts of it to try and answer the question.

What defines an illegal reflective access and what circumstances trigger the warning?

To aid in the migration to Java-9, the strong encapsulation of the modules could be relaxed.

  • An implementation may provide static access, i.e. by compiled bytecode.

  • May provide a means to invoke its run-time system with one or more packages of one or more of its modules open to code in all unnamed modules, i.e. to code on the classpath. If the run-time system is invoked in this way, and if by doing so some invocations of the reflection APIs succeed where otherwise they would have failed.

In such cases, you've actually ended up making a reflective access which is "illegal" since in a pure modular world you were not meant to do such accesses.

How it all hangs together and what triggers the warning in what scenario?

This relaxation of the encapsulation is controlled at runtime by a new launcher option --illegal-access which by default in Java9 equals permit. The permit mode ensures

The first reflective-access operation to any such package causes a warning to be issued, but no warnings are issued after that point. This single warning describes how to enable further warnings. This warning cannot be suppressed.

The modes are configurable with values debug(message as well as stacktrace for every such access), warn(message for each such access), and deny(disables such operations).


Few things to debug and fix on applications would be:-

  • Run it with --illegal-access=deny to get to know about and avoid opening packages from one module to another without a module declaration including such a directive(opens) or explicit use of --add-opens VM arg.
  • Static references from compiled code to JDK-internal APIs could be identified using the jdeps tool with the --jdk-internals option

The warning message issued when an illegal reflective-access operation is detected has the following form:

WARNING: Illegal reflective access by $PERPETRATOR to $VICTIM

where:

$PERPETRATOR is the fully-qualified name of the type containing the code that invoked the reflective operation in question plus the code source (i.e., JAR-file path), if available, and

$VICTIM is a string that describes the member being accessed, including the fully-qualified name of the enclosing type

Questions for such a sample warning: = JDK9: An illegal reflective access operation has occurred. org.python.core.PySystemState

Last and an important note, while trying to ensure that you do not face such warnings and are future safe, all you need to do is ensure your modules are not making those illegal reflective accesses. :)

Trichinize answered 9/5, 2018 at 17:40 Comment(0)
T
27

There is an Oracle article I found regarding Java 9 module system

By default, a type in a module is not accessible to other modules unless it’s a public type and you export its package. You expose only the packages you want to expose. With Java 9, this also applies to reflection.

As pointed out in https://mcmap.net/q/116282/-what-is-an-illegal-reflective-access, the differences between the AccessibleObject#setAccessible for JDK8 and JDK9 are instructive. Specifically, JDK9 added

This method may be used by a caller in class C to enable access to a member of declaring class D if any of the following hold:

  • C and D are in the same module.
  • The member is public and D is public in a package that the module containing D exports to at least the module containing C.
  • The member is protected static, D is public in a package that the module containing D exports to at least the module containing C, and C is a subclass of D.
  • D is in a package that the module containing D opens to at least the module containing C. All packages in unnamed and open modules are open to all modules and so this method always succeeds when D is in an unnamed or open module.

which highlights the significance of modules and their exports (in Java 9)

Thomson answered 9/5, 2018 at 11:8 Comment(5)
So if I read that article correctly modifying private properties in exported classes is off the table. Only protected and public properties can be modified. Now I don't care much about the java internals exports, but more about 3rd party libraries where I sometimes need access to a private variable to be set to a specific value. That would not be possible anymore in this scheme if it would define itself as a module, is that correct?Intoxicant
I don't have experience directly with that, but that would be my understanding, and read alongside the article mentioned elsewhere (jaxenter.com/jdk-9-replace-permit-illegal-access-134180.html) that would seem to be the case. Launch your JVM with –illegal-access=permit...Thomson
Well that's going to make things more interesting trying to get things to work for some things when they decide to go to the module way. Super fun times ahead.Intoxicant
For various values of funThomson
I accepted the other answer because it provided a more explanation and was more an answer to the question but sadly I can't accept two answers.Intoxicant
P
6

if you want to hide warnings you could just use "--add-opens" option

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

for example you have an error:

java.lang.ClassLoader.findLoadedClass(java.lang.String)

First open String java 11 documentation Class String where you can find module and package name

Module java.base, Package java.lang

Solution:

java --add-opens=java.base/java.lang=ALL-UNNAMED -jar example.jar
Priesthood answered 21/6, 2021 at 10:56 Comment(1)
This works for me, thank you very much !!Kai
K
2

If you want to go with the add-open option, here's a command to find which module provides which package ->

java --list-modules | tr @ " " | awk '{ print $1 }' | xargs -n1 java -d

the name of the module will be shown with the @ while the name of the packages without it

NOTE: tested with JDK 11

IMPORTANT: obviously is better than the provider of the package does not do the illegal access

Kai answered 28/6, 2020 at 23:14 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.