Java 9 distinguishes between opens and exports, and java9opensexports
Collation
This article mainly studies some precautions for migrating data to Java 9.
Migration type
- The code is not modularized. First, it is migrated to jdk9 to make good use of the jdk9 api.
- Code is also modularized for Migration
Notes
Unreadable class
For example, sun. security. x509 belongs to the java. base module in java 9, but this module does not export the package.
You can add -- add-exports java. base/sun. security. x509 = ALL-UNNAMED at runtime to modify the exports settings.
Internal class
For example, sun. misc. unsafe, which was originally intended to be used by the oracle jdk team. However, due to the wide application of these classes, Java 9 made a compromise to ensure backward compatibility, but only put these classes into jdk. the unsupported module does not limit its readability.
➜ ~ java -d jdk.unsupportedjdk.unsupported@9exports com.sun.nio.fileexports sun.miscexports sun.reflectrequires java.base mandatedopens sun.miscopens sun.reflect
Deleted class
Java 9 deletes sun. misc. BASE64Encoder. In this case, only other APIs can be used, such as java. util. Base64.
Classpath vs module-path
Java 9 introduces a module system and its own jdk is also modularized. It introduces module-path to block classpath. That is to say, the module-path is preferred in Java 9. After all, jdk is modularized, if the application is not modularized, Java 9 is implicitly modularized through the unnamed modules and automatic modules mechanisms. Of course, classpath can continue to be used on Java 9, for example, with module-path.
A jar without modularization will be assigned to unnamed modules in classpath; a module-path will be automatically created as an automatic modules (an automatic module will declare that transitive depends on all named and unnamed modules, and export its own package)
A package name cannot appear in multiple modules (split packages)
In the module, you can specify a package for exports to other modules. If multiple modules exports have the same package name, this may cause confusion. In particular, if other class libraries have both requires modules, I don't know which module to reference.
Transfer dependency
If the interface parameters or return types of a module use classes of other modules, it is recommended that the requires transitive Module
Careful cycle dependency
When designing a module, we should try our best to consider whether there will be circular dependencies. If so, we need to re-design the module.
Use services to implement optional dependency
Services is particularly suitable for decoupling the caller and implementation class dependencies. If the interface has multiple implementation classes, the caller only needs the requires interface to remove all the implementation classes of requires, use the services type to load instances that implement classes. Decoupling is achieved by dynamically adding implementation modules in module-path.
Module Version Management
The module-info.java does not support declaration of version numbers, but when creating a jar package, you can set it through -- module-version. However, the module system still uses the module name to search for the module. (If there are multiple duplicate modules in module-path, the module system will use the first module, automatically ignores subsequent modules with the same name). Version dependency issues are not resolved by the module system and are managed by dependency management tools such as maven.
Module Resource Access
After modularization, resource files are also protected. You can only access the resource files of this module by this module. If you need to access these files across modules, you must use ModuleLayer to find the target module, then, call the target module to load the resource files of the module.
Use of reflection
This involves the deep reflection problem. The so-called deep reflection is to call a non-public element of a class through reflection. The module-info.java's exports declares that the package only allows the class that the package directly belongs to allow access to its public element and does not allow reflection to call non-public elements.
Reflection in the module system requires a special declaration to allow use (use opens declaration to allow deep reflection). As a result, many reflection class libraries, such as spring, need additional configuration to be migrated to Java 9. There are two solutions: one is the opens package name to be reflected by the module, such as spring. beans, and the other is the entire opens module.
The default value is -- illegal-access = permit. At the same time, this setting only applies to packages before Java 9 that are not allowed to be accessed in Java 9. It is not applicable to packages that are not allowed to be accessed in Java 9. (It is recommended to set it to deny when migrating to a modular system)
However, in the module system, the package names are different and there is no inheritance relationship, such as com. service. func1 and com. service. func2 is a different package. You cannot only use opens com. service, which must be specified separately, resulting in more open packages. Therefore, opening the entire module may be easier, but it is also a Rough practice.
The above approach is to make changes in the original module-info.java, the other is to execute java or javac through the specified command to modify the original relationship. For example
java ... --add-opens source-module/source-package=target-module
If you want to export to unnamed modules, the target-module is ALL-UNNAMED.
Of course, if it is a new system, we do not recommend using reflection. You can use MethodHandles and VarHandles.
FAQs and measures
ClassNotFoundException/NoClassDefFoundError
For example, javax. xml. bind. JAXBException, JAXB has been included in the java. xml. bind module and added after the java name
--add-modules java.xml.bind
If the graph saves time, add $ JAVA_HOME and all third-party class libraries to module-path and
--add-modules ALL-MODULE-PATH
Illegal reflective access by xxx to method java. lang. ClassLoader. defineClass
Cause of reflection. Because the old system does not have module-info, add a parameter in the java name to modify it.
--add-opens java.base/java.lang=ALL-UNNAMED
Determine the dependent Module
Analysis through IDE or jdeps
jdeps --class-path 'classes/lib/*' -recursive -summary app.jar
Jdeps is only static code analysis. If the class jdeps used for reflection cannot be analyzed, manually requires is required. If the dependency is optional, requires static
Readability of module Unit Tests
If a unit test is a separate module, you can use -- add-exports or -- add-opens to grant the unit test module the readability and reflection capabilities of the target module at runtime. In addition, due to the split packages problem, the package name of the unit test class cannot be the same as the package name of the target module. The original maven Project test
Summary
You can migrate data to Java 9 in two steps. First, it is not modularized, but it is run on JDK 9 first, and then modularized.