This article mainly studies some matters needing attention in migrating to java9.
1. The code is not modularized. First, migrate to jdk9 to make good use of the api of jdk9
2. The code is also migrated modularly.
Several Points for Attention
For example, sun.security.x509 is included in java.base module in java9, but this module does not export this package.
You can modify the export settings by adding-add-exports java.base/sun.security.x509=ALL-UNNAMED at runtime.
For example, sun.misc.Unsafe originally only wanted oracle jdk team to use it. However, due to the wide application of these classes, java9 made a compromise for backward compatibility. It just classified these classes into jdk.unsupported modules and did not limit their readability.
➜ ~ java -d jdk.unsupported jdk.unsupported@9 exports com.sun.nio.file exports sun.misc exports sun.reflect requires java.base mandated opens sun.misc opens sun.reflect
Java9 has deleted sun.misc.BASE64Encoder, which can only be changed to other apis, such as java.util.Base64
classpath vs module-path
Java9 has introduced a module system and its own jdk has also been modularized. module-path is introduced to shield classpath. That is to say, module-path is preferred in java9. After all, jdk itself is modularized. If the application itself is not modularized, java9 implicitly modularizes through unnamed modules and automatic modules mechanisms. Of course, classpath can still be used on java9, for example, it can be used in conjunction with module-path.
Jars without modularity will be classified as unnamed modules； in classpath; The module-path will be automatically created as automatic modules (
An automatic modules declares that transitive depends on all named and unnamed module, and then exports its own package.)
A package name cannot appear in multiple modules (
Because modules can export packages to other modules, if multiple modules export the same package name will cause confusion, especially if other class libraries requires both modules at the same time, you don’t know which module to reference.
If the interface parameters or return types of one module use the classes of other modules, it is recommended that requires transitive the modules it depends on.
Careful circular dependence
When designing a module, it is necessary to consider whether there will be circular dependency or not, and if so, it needs to be redesigned.
Use services to implement optional dependencies.
Services is especially suitable for decoupling the dependency between the caller and the implementation class. If the interface has multiple implementation classes, the caller does not need to requiress all the implementation classes, but only needs the requirements interface, and uses the service type to load the instance of the implementation class. Decoupling is realized by dynamically adding implementation modules in module-path.
Module version management
Module-info.java does not support declaring version numbers, but when creating jar packages, you can set them through –module-version. However, the module system still uses the module name to find the module (
If there are multiple modules with the same name in the module-path, the module system informs the user to use the first one found and automatically ignores the subsequent modules with the same name), version dependency problem is beyond the scope of module system solution, and is managed by dependency management tools such as maven.
Module resource access
After modularization, the resource files are also protected. Only the module can access the resource files of the module itself. If cross-module access is required, the target module must be found by means of ModuleLayer, and then the target module is called to load the resource files of the module.
Use of reflection
This involves the problem of deep reflection, which is to call a class’s non-public element by reflection. Module-info.java’s exports declares that package only allows classes to which the package directly belongs to access its public element, and does not allow reflection calls to non-public elements.
Reflection requires special declaration in the module system to allow use (
Use opens declaration to allow deep reflection), which results in many class libraries that use reflection, such as spring, requiring additional configuration to migrate to java9. There are two solutions: one is to give OpenPackage package name to modules that need reflection, such as spring.beans, etc. One is direct opens whole module.
Default –illegal-access=permit = permit, and this setting is only applicable to packages before java9 that are not allowed to access in java9, and is not applicable to new packages that are not allowed to access in java9. (
It is recommended to set it to deny when migrating to a modular system)
However, in the module system, packages with different names belong to different packages, and there is no inheritance relationship. For example, com.service.func1 and com.service.func2 are two different packages. You cannot only use OpenSC.service, but you must specify them separately, which leads to more packages that need to be open. Therefore, it may be easier to open the whole module, but it is also a rougher approach.
The above method is to make changes in the original module-info.java , and the other is to modify the original relationship through specified commands when executing java or javac. such as
java ... --add-opens source-module/source-package=target-module
If you need to export to unnamed modules, the target-module is ALL-UNNAMED
Of course, if it is a new system, it is not recommended to use reflection. You can use MethodHandles and VarHandles.
Common Problems and Measures
For example, JAXBx.xml.bind.JAXBException, which has been included in java.xml.bind module, is added after java naming.
If it is convenient, add $JAVA_HOME and all third-party class libraries to the module-path, and then add one
illegal reflective access by xxx to method java.lang.ClassLoader.defineClass
The reflection reason is that since the old system did not have module-info, parameters were added to java naming to modify it.
Identify dependent modules
Through IDE or jdeps analysis
jdeps --class-path 'classes/lib/*' -recursive -summary app.jar
Jdeps is only static code analysis. If there is a reflection class jdeps that cannot be analyzed, you need to manually require it. If dependency is optional, you can requires static
Readability of Module Unit Testing
If the unit test is a separate module, the readability and reflection ability of the unit test module to the target module can be granted through –add-exports or –add-opens at runtime. In addition, due to the split packages problem, the package name of the unit test class cannot be duplicated with the package name of the target module. The original maven project test
You can migrate to java9 in two steps. First, you will not be modularized but will only run on jdk9 first. And then modular.