- 9.1 The Module Concept
- 9.2 Naming Modules
- 9.3 The Modular "Hello, World!" Program
- 9.4 Requiring Modules
- 9.5 Exporting Packages
- 9.6 Modular JARs
- 9.7 Modules and Reflective Access
- 9.8 Automatic Modules
- 9.9 The Unnamed Module
- 9.10 Command-Line Flags for Migration
- 9.11 Transitive and Static Requirements
- 9.12 Qualified Exporting and Opening
- 9.13 Service Loading
- 9.14 Tools for Working with Modules
9.10 Command-Line Flags for Migration
Even if your programs do not use modules, you cannot escape the modular world when using Java 9 and beyond. Your application code may reside on the class path in an unnamed module, so that all packages are exported and opened. Still, the code interacts with the Java platform, which is modularized.
As of Java 11, compile-time encapsulation is strictly enforced. However, before Java 16, runtime access was permitted. The default behavior was to display a warning on the console for the first instance of each offense. As of Java 16, reflective access at runtime is also enforced. In order to give you time to prepare for that change, the java launcher in Java 9 through 16 had an --illegal-access flag with four possible settings:
--illegal-access=permit is the Java 9 default behavior, printing a message for the first instance of illegal access.
--illegal-access=warn prints a message for each illegal access.
--illegal-access=debug prints a message and stack trace for each illegal access.
--illegal-access=deny is the Java 16 default behavior, denying all illegal access.
The --illegal-access flag is no longer usable in Java 17.
The --add-exports and --add-opens flags allow you to tweak legacy applications. Consider an application that uses an internal API which is no longer accessible, such as com.sun.rowset.CachedRowSetImpl. The best remedy is to change the implementation. (As of Java 7, you can get a cached row set from a RowSetProvider.) But suppose you don't have access to the source code.
In that case, start the application with the --add-exports flag. Specify the module and the package that you want to export, and the module to which you want to export the package, which in our case is the unnamed module.
java --add-exports java.sql.rowset/com.sun.rowset=ALL_UNNAMED -jar MyApp.jar
Now, suppose your application uses reflection to access private fields or methods. Reflection inside the unnamed module is OK, but it is no longer possible to reflectively access non-public members of the Java platform classes. For example, some libraries that dynamically generate Java classes call the protected ClassLoader.defineClass method through reflection. If an application uses such a library, add the flag
--add-opens java.base/java.lang=ALL-UNNAMED
When adding all those command-line options to get a legacy app to work, you may well end up with the command line from hell. To better manage multiple options, you can put them in one or more files specified with an @ prefix. For example,
java @options1 @options2 -jar MyProg.java
where the files options1 and options2 contain options for the java command.
There are a few syntax rules for the options files:
Separate options with spaces, tabs, or newlines.
Use double quotes around arguments that include spaces, such as "Program Files".
A line ending in a \ is merged with the next line.
Backslashes must be escaped, such as C:\\Users\\Fred.
Comment lines start with #.