対象読者
- Java関連に携わる開発者
- これからJavaを学ぼうと思っている方
既存のライブラリ資産を利用する場合
Javaにはこれまで蓄積されたライブラリも多く、特にオープンソースライブラリを使わない選択をするのは、多くのプロジェクトで難しいと言わざるを得ません。そしてJava 9へのバージョンアップ後も、それらのライブラリをそのまま使う必要があるケースが多々あります。
しかし、Java 9がモジュールに対応したことに合わせて、既存の全ての資産をモジュール対応させてリリースし直すのは、現時点では難しいことでしょう。
Java 9のモジュール機能とモジュール対応されていないライブラリを同時に利用することは可能です。しかし、そのためにはいくつかの注意点があり、Java 9がモジュールをどのように扱っているのか、理解する必要があります。
Java 9におけるモジュールの扱い
Java 9のモジュールは、以下の3種類に分類できます。
[1]Named Module(Platform Module/Application Module)
Java 9のモジュール機能形式に沿ったモジュールです。このモジュールにはJDKで提供されているPlatform Moduleとそれ以外のApplication Moduleが存在しますが、基本的な制限事項は同じです。
ただし、Platform Moduleのjava.baseは全てのコードに依存してしまうため、このモジュールのみ例外としてどのモジュールからも自由にアクセス可能です。また、Application Moduleはモジュールパス(実行時に--module-pathで指定されたパス)に配置する必要があります。
[2]Automatic Module
この形式は、Java 9以前の形式(module-info.classファイルがない)でパッケージングされたjarファイルがモジュールパスに配置された際、自動的にモジュール扱いになるものです。
モジュール名は「ファイル名から自動的に命名」されるか、「manifestファイル内のAutomatic-Module-Name属性で指定」します。
ファイル名から自動的に命名される場合
ファイル名から命名される場合には、ルールに従います。具体的には以下の通りです。
- 最後の.jarの拡張子を削除します。
- ファイル名にハイフンが含まれて、そのハイフン以降が数値もしくはドットの場合(正規表現で「-(\d+(\.|$))」に一致する場合)、最初のハイフン以前の部分を利用します。
- 英数字でない文字(ハイフンなどの記号)は、全てドットに置き換えます。
つまり、「sample-foo.jar」という名前のjarファイルは「sample.foo」というモジュール名になり、「sample-foo-2.0.1.jar」というファイル名の場合も「sample.foo」というモジュール名になるということです。
manifestファイル内のAutomatic-Module-Name属性で指定する場合
manifestファイル内でモジュール名をsample.fooと指定する場合には、リスト1の通りにします。
Automatic-Module-Name: sample.foo
どちらの方法で命名されたとしても、このjarファイル内で定義されたパッケージは自動的に全てexportsされたものとして扱われます。これは、その他のモジュールに依存していることも多く、そこで定義が必要になってしまわないためにも必要な扱いといえます。
[3]Unnamed Module
このモジュールはクラスパスに指定された場合のモジュールです。また、Unnamedとあるようにモジュール名はありません。通常ここに配置されるのはAutomatic Moduleが依存しているライブラリです。
Application Moduleがコンパイルされる際に、Automatic ModuleとUnnamed Moduleにどのような制限があるかを示したのが図1です。
この通り、Unnamed Moduleは参照できません。つまり、コンパイル時にパッケージやクラスが見つからないことになります。したがって、コード内で既存のjarファイル内のクラスにアクセスする場合には、そのjarファイルをモジュールパス内に移動し、Automatic Moduleとして扱う必要があります。
ただし実行時はコンパイル時と異なり、リフレクションを使ったクラスへのアクセスが可能なため、コンパイル時に問題が生じなくても、実行時にはエラーが発生するケースがあります。
また、Java 9に以前に作られたライブラリは、Platform Moduleのjava.base以外も全て、何も制限なく参照可能でした。つまり、Java 9以前に作られたライブラリの場合は、ライブラリの中身を何も変更せずにそのまま利用したい事が多いと思います。そのためには、Javaの実行時にコマンドオプションに以下の指定し、モジュールへの参照権限の指定が必要になります。
--add-modules module(,module, ...)
実行時にモジュールの追加が可能です。
--add-exports module/package=target-module(,target-module, ...)
実行時に、<module>/<package>を<target-module>からアクセス(exports)できるようにします。
--add-opens module/package=target-module(,target-module, ...)
実行時に、<module>/<package>を<target-module>からアクセス(opens)できるようにします。
これらの関係を示したのが図2です。