はじめに
- Oracle Certified Java Programmer, Silver SE 11 認定資格の受験にあたり、Java11について学習/検証した内容を資料としてまとめる。
- 本ドキュメントは、出題範囲のうち、以下出題範囲に対応する調査を行った結果となる。
- モジュール・システム
本ドキュメントで解説する内容
- モジュール
- モジュールの構成
- モジュールのコンパイル
- モジュールの実行
- モジュール情報の確認
- クラス/モジュールの依存関係確認
- 非公開パッケージの一時的な公開
- module-info.java
モジュール
- 「モジュール」とは複数のパッケージ(主にライブラリなど)を管理する単位となる(Java9以降)
- モジュールを利用することで、パッケージ単位でモジュール外への公開/非公開を管理できる。
- モジュール内部でのみ利用しているパッケージが、他のコードからアクセスできないようにする用途などに利用する。
- 標準ライブラリもモジュールとして提供されており、基本的なAPIは
java.base
として全モジュールに提供される。 - モジュール化されていないアプリケーションは、実行時には暗黙的に無名モジュールに属していると見做され、全モジュールを読み込み、全パッケージを公開する。
モジュールの構成
- srcディレクトリ配下にモジュール用のディレクトリ(下記例だとmymodule)を作成する。
- モジュール用ディレクトリにおいて、
module-info.java
、およびモジュールのソースを含む。
src
└── mymodule
├── com
│ └── sample
│ ├── A.java
│ └── B.java
└── module-info.java
モジュールのコンパイル
- モジュール用のディレクトリに配置した
module-info.java
を他のソースと共にコンパイル(javacコマンド)する。javac -d [クラスファイルの出力先ディレクトリ] [コンパイルするファイルのパス] 例: $ javac -d src/mods/mymodule src/mymodule/module-info.java src/mymodule/com/sample/*.java src └── mods └── mymodule ├── com │ └── sample │ ├── A.class │ └── B.class └── module-info.class
- モジュールのクラスファイルをJARファイルとしてまとめる(jarコマンド)ことも可能。
jar --create --file=[JARファイルのパス] --main-class=[エントリーポイントクラス] -C [クラスファイルが存在するディレクトリ] 例: $ jar --create --file=mlib/mymodule.jar --main-class=com.sample.A -C src/mods/mymodule . mlib └── mymodule.jar
- モジュールのクラスファイルをJMODファイルとしてまとめる(jmodコマンド)ことも可能。
jmod create --class-path [クラスファイルが存在するディレクトリ] [JMODファイルのパス] 例: $ jmod create --class-path src/mods/mymodule mlib/mymodule.jmod mlib └── mymodule.jmod
モジュールの実行
- javaコマンドを
--module-path
および-m
を指定して実行する。 - メインクラスが指定されたJARファイルにアーカイブされたモジュールの場合、クラスは指定不要。
$ java --module-path [モジュールのルートディレクトリ] -m [モジュール名/モジュールのクラス]
例:
$ java --module-path src/mods -m mymodule/com.sample.A
$ java --module-path mlib -m mymodule
モジュール情報の確認
モジュール情報(module-info.java
に定義した内容)を確認する方法は以下の2種類となる。
- javaコマンドを
--module-path
および--describe-module
を指定して実行する。$ java --module-path [モジュールのルートディレクトリ] --describe-module [モジュール名] 例: $ java --module-path src/mods --describe-module mymodule mymodule file:///opt/src/mods/mymodule/ requires java.base mandated contains com.sample
- jmodコマンドを
describe
で実行する。$ jmod describe [JMODファイルのパス] 例: $ jmod describe mlib/mymodule.jmod mymodule requires java.base mandated contains com.sample
クラス/モジュールの依存関係確認
- クラスおよびモジュールの依存関係(
module-info.java
でrequired定義した内容)を確認する方法は以下の2種類となる。
- クラス/モジュールの依存関係を確認するにはjdepsコマンドを
--list-deps
を指定して実行する。$ jdeps --list-deps [JARファイルのパス] 例: $ jdeps --list-deps mlib/mymodule.jar java.base
- モジュールの依存関係を確認するにはjavaコマンドを
--show-module-resolution
で実行する。$ java --module-path [モジュールのルートディレクトリ] -m [モジュール名/モジュールのクラス] --show-module-resolution 例: $ java --module-path src/mods -m mymodule/com.sample.A --show-module-resolution root mymodule file:///opt/src/mods/mymodule/ java.base binds java.smartcardio jrt:/java.smartcardio java.base binds java.naming jrt:/java.naming java.base binds jdk.security.jgss jrt:/jdk.security.jgss ...
非公開パッケージの一時的な公開
- javacコマンドを
--add-exports
を指定して実行することで、非公開のパッケージを一時的に公開できる。
$ javac javac -d [クラスファイルの出力先ディレクトリ]
--module-path [モジュールのルートディレクトリ]
--add-exports [対象のモジュール/公開するパッケージ=利用するモジュール]
[コンパイルするファイルのパス]
例:
$ javac -d mods/mymodule
--module-path mods/ \
--add-exports mymodule/com.sample=app \
src/app/module-info.java src/app/com/Main.java
module-info.java
- モジュールの公開・依存・サービス・リフレクションを定義する。
module mymodule { //任意のオペレーションを記載 }
- 記載できるのは以下となる。
- exports系: モジュール外に公開するパッケージを指定する。
- requires系: モジュールが利用(依存)する外部モジュールを指定する。
- uses/provides: サービス(インタフェースの実装)の利用/提供を指定する。
- open系: リフレクションの利用を許可する。
Directive | Sumary |
---|---|
requires | 指定したモジュールをロードする(モジュール依存性) |
requires static | コンパイル時はモジュールが必要だが、実行時には省略可能(オプション依存性) |
requires transitive̶ | 推移的ロード(指定したモジュールが依存するモジュールもロードする) |
exports | パッケージをエクスポートする(当該パッケージのpublic型に対して、他のモジュールからアクセスできる) |
exports…to | エクスポートされたパッケージにアクセス可能なモジュール一覧をカンマ区切りで指定する(制限付きエクスポート) |
uses | モジュールが使用するサービス(インタフェース名/抽象クラス名)を指定する |
provides…with | サービスの実装(インタフェース定義および実装)を提供する(サービスプロバイダ) |
open | module定義にopenを付加することで、リフレクションによる強制アクセスを許可する(モジュール単位) |
opens | リフレクションによる強制アクセスを許可する(パッケージ単位) |
opens…to | リフレクション許可パッケージにアクセス可能なモジュール一覧をカンマ区切りで指定する(制限付きパッケージ単位) |
module-info.java
[open] module <モジュール名> {
requires <外部モジュール名>; // モジュールのロード(モジュール依存性)
requires static <外部モジュール名>; // オプション依存性
requires transitive <外部モジュール名> // モジュールの推移的ロード(モジュール依存性)
exports <パッケージ名> // 制限なしエクスポート
exports <パッケージ名> to <外部モジュール名>,<外部モジュール名> // 制限付きエクスポート
use <インタフェース名/抽象クラス名> // サービスの利用 (サービスコンシューマ)
provides <インタフェース名/抽象クラス名> with <実装クラス名> // サービスの提供 (サービスプロバイダ)
opens <パッケージ名> // リフレクションの許可(制限なし)
opens <パッケージ名> to <外部モジュール名>,<外部モジュール名> // リフレクションの許可(制限付き)
}