Better tools for adjusting to strong encapsulation

By now we've heard quite a bit of feedback, both publicly and privately, from developers who've migrated existing applications to JDK 9. This can be a non-trivial task, involving the iterative construction of a set of command-line workarounds, since some popular libraries and frameworks use the core reflection API to access internal APIs of the JDK. On JDK 9 such components no longer work out-of-the-box because most internal APIs are now strongly encapsulated in order to improve the integrity of the platform. In order to make it easier to adjust to the strong encapsulation of internal APIs in JDK 9, in both the short term and over the long term, we've introduced a temporary "big kill switch", described below. This switch will only be supported in JDK 9. It's already available in the current Jigsaw EA builds [1], and will shortly be merged into JDK 9. Background ---------- Diagnosing the failures of libraries and frameworks that access internal APIs of the JDK and then working around those failures is possible, but tedious. The initial symptom is usually an `IllegalAccessException` or an `InaccessibleObjectException`. The workaround is to use an `--add-opens` command-line option whose arguments are based upon the information shown in the exception message. A large application that uses several reflective components may suffer many such failures, so this process may have to be repeated many times, resulting in a long list of command-line options that will typically be recorded in a launch script or an @-file. These options are tedious to construct but, additionally, there's a significant risk that once they're baked into a file they'll never be removed, even long after the problems that they work around have been resolved. An application that needs some workarounds today might not benefit as well as it could from strong encapsulation in the long term, after all of the reflective components that it uses have been fixed to replace their use of JDK-internal APIs with proper exported APIs. To help the entire ecosystem migrate to the modular Java platform we want to motivate such fixes as strongly as we possibly can, especially in the near term. We can do that by making it easier for you to get an existing application to work while also ensuring that the run-time system reports illegal reflective-access operations in a way that allows you to identify which libraries and frameworks on your class path require illegal access in order to work. If a component's maintainers have already released a new, fixed version that no longer requires illegal access then you can consider upgrading to that version. If, however, a component still needs to be fixed then we encourage you to contact its maintainers and ask them to stop using JDK-internal APIs [2]. With all this in mind we've introduced a "big kill switch", described below, together with some new warning messages. This switch will be supported in JDK 9, in order to enable application migration and motivate fixes to libraries and frameworks. It will not be supported in JDK 10 or later releases, in order to motivate fixes to libraries and frameworks sooner rather than later. If this switch were to be supported long-term then that would tend to reduce the pressure on maintainers to fix their components. New command-line option: `--permit-illegal-access` -------------------------------------------------- If this option is present at run time then it will permit illegal access operations by code in any unnamed module (i.e., code on the class path) to members of types in any named module via the standard reflective APIs (`java.lang.reflect` and `java.lang.invoke`), including in particular those that would otherwise result in an `IllegalAccessException` or an `InaccessibleObjectException`. +----------------------------------------------+ | This option will only be supported in JDK 9. | | It will be removed in JDK 10. | +----------------------------------------------+ This option does not permit illegal access operations by code in named modules to members of types in other named modules; for that you must use the `--add-opens` or `--add-exports` options. Those options can be combined with `--permit-illegal-access`. Warnings of illegal reflective-access operations ------------------------------------------------ When an illegal reflective access operation succeeds due to the use of the `--permit-illegal-access` option, or the use of an `--add-opens` or `--add-exports` option, then a warning message of the following form is written to the error stream: WARNING: Illegal access by $PERPETRATOR to $VICTIM (permitted by $OPTION) 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, - $VICTIM is a string that describes the member being accessed, including the fully-qualified name of the enclosing type, and - $OPTION is the name of the command-line option that enabled this access, when that can be determined, or the first one of those options if more than one option had that effect. The run-time system attempts to suppress duplicate warnings for the same $PERPETRATOR and $VICTIM, but it's not always practical to do so. For deeper diagnosis you can request a stack trace on each such warning by setting the system property `sun.reflect.debugModuleAccessChecks` to the value `access`, though this detail might change. (That property can also be helpful to diagnose mysterious failures due to illegal-access exceptions that are caught and suppressed.) In addition to displaying a warning on each illegal access operation, the run-time system also shows new initial warning messages at startup time. If `--permit-illegal-access` is used then a warning reports the imminent demise of that option in the next major release. If either `--add-opens` or `--add-exports` are used then a warning reports a count of each type of option used (i.e., opens vs. exports). Here are some examples of these messages, from running Jython on a very recent Jigsaw build: $ java --permit-illegal-access -jar jython-standalone-2.7.0.jar WARNING: --permit-illegal-access will be removed in the next major release WARNING: Illegal access by jnr.posix.JavaLibCHelper (file:/tmp/jython-standalone-2.7.0.jar) to method sun.nio.ch.SelChImpl.getFD() (permitted by --permit-illegal-access) WARNING: Illegal access by jnr.posix.JavaLibCHelper (file:/tmp/jython-standalone-2.7.0.jar) to field sun.nio.ch.FileChannelImpl.fd (permitted by --permit-illegal-access) WARNING: Illegal access by jnr.posix.JavaLibCHelper (file:/tmp/jython-standalone-2.7.0.jar) to field java.io.FileDescriptor.fd (permitted by --permit-illegal-access) WARNING: Illegal access by org.python.core.PySystemState (file:/tmp/jython-standalone-2.7.0.jar) to method java.io.Console.encoding() (permitted by --permit-illegal-access) Jython 2.7.0 (default:9987c746f838, Apr 29 2015, 02:25:11) [OpenJDK 64-Bit Server VM (Oracle Corporation)] on java9-internal Type "help", "copyright", "credits" or "license" for more information. >>> ^D $ [1] http://openjdk.java.net/projects/jigsaw/ea [2] This will usually but not always be possible, since there are still a few critical internal APIs without exported replacements, per JEP 260 (http://openjdk.java.net/jeps/260).