[Java] Module
What is a module?
- Package superordinate concept
- Constitution
- ** Packages and related resources **
- Module definition file that defines its own configuration information **
Traditional packaging issues
Access authority cannot be set for each package
- For packages that are supposed to be used inside the library, I want to prevent access from outside the library.
- But there is no way to make the ** public class for internal use invisible **
.jar file cannot represent dependencies
- Multiple packages are combined as a .jar format compressed file and provided as a library.
- But .jar cannot express dependencies between libraries
- In the .jar ** I don't know what type of API is supposed to be used from the outside or which library is needed for operation **
Solved by using modules!
- ** Bundle specific libraries and frameworks into groups **
- Modular libraries allow finer management of public classes
- ** Public ** only in the current module
- ** Public ** only for specific modules
- ** Public for all modules (same as before) **
Module basic
- Module definition file description in ** module-info.java ** directly under / sec
- ** List the packages that the module depends on, the package information that is exposed to the outside **
- If you do not declare the required libraries in require,
The type java.net.http.HttpRequest is not accessible
module-info.java
//Module name foo
//java in foo module.net.need http
module foo {
requires java.net.http;
requires mylib;
requires gson;
}
Standard library module
- The standard library is also modularized
Basic module
- java.base
- It is troublesome to add the standard library one by one, so ** Frequently used packages are grouped in the java.base module **
- The java.base module is implicitly loaded so no explicit requires declaration is required
- There is also a ** java.se module ** that defines the entire Java standard library, but it also loads unnecessary modules.
Transitive dependence
- ** Transitive **: If the loaded module is dependent on another module, the dependent destination is also loaded.
- ** requires transitive ** to solve transitive dependence nicely
module-info.java
module java.se {
requires transitive java.compiler;
requires transitive java.datatranfer;
requires transitive java.desktop;
//Abbreviation
}
Package release
- If you want to publish your package
- There are packages that you want to publish to the outside (lib) and packages that you want to use in the library (internal)
- ** Only libraries published in exports directive ** can be published externally
module-info.java
module mylib {
exports mylib.lib;
}
//OK
import mylib.lib.MainLib;
//NG! interna;Package is invisible
//import mylib.internal.Sublib;
public class ModuleClient {
public static void main(String[] args) {
var main = new MainLib();
main.run();
}
}
module foo {
requires java.net.http;
requires mylib;
requires gson;
}
Package release only for specific modules
- ** exports package to module **
- In the following cases, the lib package is only exposed to the foo module
- Multiple publication destinations can be specified with
,
module-info.java
module mylib {
exports mylib.lib to foo;
}
open private method
- ** Deep Reflection **: Forced access using reflection
- Deep reflection is not possible with module exports alone
import java.lang.reflect.InvocationTargetException;
import mylib.lib.MainLib;
public class ModuleClient2 {
public static void main(String[] args) {
try {
var clazz = MainLib.class;
var con = clazz.getConstructor();
var m = con.newInstance();
var name = clazz.getDeclaredField("name");
name.setAccessible(true); //error
System.out.println(name.get(m));
} catch (InstantiationException | IllegalAccessException |
IllegalArgumentException | InvocationTargetException
| NoSuchMethodException | SecurityException | NoSuchFieldException e) {
e.printStackTrace();
}
}
}
Declare the package with the ** opens directive ** and solve it!
- Publish the package only at runtime
- When referencing a type other than reflection, also include the exports directive.
- **
open module mylib {
** makes all packages under the module open
module-info.java
module mylib {
opens mylib.lib;
exports mylib.lib;
}
Special module
- Pseudo-module concepts are also provided
- ** Automatic module **
- ** Anonymous module **
Automatic module
- .Jar file placed in the module path
- A library that does not have
module-info.java
Determined from manifest information
- Makes the name specified in ** Automatic-Module-Name attribute ** of the manifest file (META-INF / MANIFEST.MF) the module name.
MANIFEST.MF
Manifest-Version: 1.0
Automatic-Module-Name: hoge.bar
Determined by .jar file name
- Naming convention
- Remove extension
.jar
- If the characters after the hyphen are only numbers / dots, delete after the hyphen
- Convert non-alphanumeric characters to
.
- Repeat dots are single dots, leading / trailing dots are removed
- ex: hoge-bar-1.0.5.jar is ** hoge.bar **
- Operating rules
- ** Exports / opens all packages under it **
- ** All modules registered in the module path and anonymous modules are required **
- ** Requires required to use packages exported / opened by automatic module from other modules **
Anonymous module
- .Jar file placed in the classpath
- Does not have a module name
- At compile time ** Cannot be referenced from application modules **
- ** Reference from automatic module is possible **
- ** Application module **: Module with module-info.java
- ** Platform module **: Modules that make up the standard library
Coexistence with non-module libraries
- ** Use non-module libraries from modular apps **
- The following ** Gson library ** converts Java objects to JSON-formatted strings
- java.sql package dependent
- Deep reflection on the Java object to be converted
- You cannot access the java.sql.Time class without a reference to the java.sql module used internally by Gson.
//NG example Run-time error
import com.google.gson.Gson;
public class NoModuleLib {
public static void main(String[] args) {
var g = new Gson();
var a = new Article("Java 11 changes", "https://codezine.jp/article/corner/751");
//Output the result of converting the object contents to JSON
System.out.println(g.toJson(a));
}
}
Article.java
public class Article {
private String title;
private String url;
public Article(String title, String url) {
this.title = title;
this.url = url;
}
@Override
public String toString() {
return String.format("title:%s(%s)",
this.title, this.url);
}
}
Explicitly add module with execution option
- In the VM argument of the execution configuration
- **
--add-opens = module name / package name = module to allow access
**
--add-modules=java.sql --add-opens=foo/example=gson
- Make the example package of the foo module accessible from the gson library