Java Module Systemとは

Java SE 7における重要な機能強化のひとつとしてモジュラリティのサポートが挙げられている。その核となるのが「JSR 294: Java Language Modularity Support with Superpackage」と「JSR 277: Java Module System」の2つのJSRである。両者はお互いに密接に関係しているが、区分としてはJSR 294が「開発時のモジュラリティ」、JSR 277が「配付時のモジュラリティ」を提供するものという位置づけになっている。

このうち、JSR 294についてはJavaOneレポートでテクニカルセッションの様子を紹介したので、そちらを参照していただきたい。今回はJava Module Systemについて紹介したいと思う。

現在、Javaアプリケーションの配布にはJAR(Java ARchive)が使用されている。しかしJARの規格が制定されたのはまだJavaが若かったころのことであり、バージョン管理や依存関係の解決をサポートしていないなど、現在のアプリケーションに適用するには不十分な部分が多い。JSR 277ではこういったJARの問題を解決するために、新しい配布単位としてのモジュールシステムを検討している。

具体的には、Java Module Systemでは主に次のような機能が提供される予定だ。

  • 新しいメタデータ形式を含む配布単位(JAM)
  • バージョン管理スキーム
  • モジュール管理のためのリポジトリ
  • クラスローダやアプリケーションランチャにおける実行時サポート
  • 各種サポートツール

JSR 277は現在JCPのサイトにおいてEarly Draftが公開されている。

Java Application Module

Java Application Module(JAM)はJSR 277で規定される、JARに替わるJavaアプリケーションの新しい配布単位である。JAMは名前、インポートするモジュール、エクスポートするクラス、メンバ、拡張メタデータからなる新しい形式のメタデータを保持する。モジュール名は「org.foo.xml」のような形式で表される。また拡張メタデータはバージョン情報やメインクラス名、属性などの情報を持つ。

他のモジュールのインポートや、モジュール内のクラスのエクスポート宣言については、リスト1およびリスト2のようなコード例が示されている。

インポートの宣言例

// org.foo.soapモジュールをインポート
superpackage org.foo.xml {
    import org.foo.soap;
}

// バージョンを指定したオプションインポート
superpackage org.foo.xml {
    @Optional
    @VersionConstraint("1.3")
    import org.foo.soap;
}

// 再エクスポート
superpackage org.foo.xml {
    @Reexport
    import org.foo.soap;
}

エクスポートの宣言例

@Version("1.2.3")
@ExportResources({
    "icons/graphics1.jpg", 
    "icons/graphics2.jpg"})
superpackage org.foo.xml {
    export org.foo.xml.*;
}

アプリケーションモジュールは.jamという拡張子を持つJAMファイルとして配布される。JAMファイルのファイル名は次のようにする。

<名前>-<バージョン>[-<プラットフォーム>-<アーキテクチャ>].jam

たとえばx86 Linux向けorg.foo.xmlモジュールのバージョン1.2.3ならば、「org.foo.xml-1.2.3-linux-x86.jam」のようになる。JAMファイルの中にはメタデータ、ネイティブライブラリ、JARファイル、クラスやファイルなどのリソースが含まれ、リスト3のような構成になる。

リスト3 JAMファイルの構成例

org.foo.xml-1.2.3.jam:
        /META-INF/MANIFEST.MF
        /MODULE-INF/METADATA.module        ←メタデータ
        /MODULE-INF/bin/xml-linux.so       ←ネイティブライブラリ
        /MODULE-INF/lib/xml-parser.jar     ←JARファイル
        /org/foo/xml/org.foo.xml.spkg
        /org/foo/xml/ClassA.class
        /org/foo/xml/ClassB.class
        /org/foo/xml/ClassC.class
        /isons/graphics1.jpg
        /icons/graphics2.jpg

この構成を見てもわかるように、既存のJAR規格はJAMに内包される形式になっており、なくなるわけではない。

リポジトリの導入

リポジトリはモジュールの格納や検索を行うためのメカニズムで、アプリケーションにおけるモジュールの管理をサポートする。Java Module Systemのリポジトリは複数バージョンのモジュールの同時インストールやside-by-side配置を可能にする。

リポジトリには複数の種類があり、Early Draftでは下記のようなものが挙げられている。

  • Bootstrapリポジトリ - モジュールシステムの基本となるリポジトリ
  • Globalリポジトリ - システムごとに用意されるリポジトリ
  • Applicationリポジトリ - アプリケーションごとのリポジトリ
  • Localリポジトリ - ローカルファイルのコードベースによって管理されるリポジトリ
  • URLリポジトリ - URL形式のコードベースによって管理されるリポジトリ

通常はBootstrap-Global-Applicationという階層構造を持つ。ひとつのリポジトリが複数の子リポジトリを持つこともできる。リポジトリの階層構造は移譲モデルを採用しており、下位のリポジトリでモジュール定義が要求された場合でも上の階層まで遡って検索する。

他のJSRとの互換性

前述の通り、JSR 277はJSR 294と密接に関係している。たとえばJSR 294で定められるSuperpackageの規格がJAMの仕様に影響を与えるといったこともあるため、両者を切り離して考えることはできない。また、JSR 277はJSR 291:Dynamic Component Support for Java SEとも関連している。JSR 291はOSGiから提唱されているダイナミックコンポーネントモデル仕様をベースにしたフレームワークで、パッケージ間の依存関係の解決をサポートする。

そのため、これらJSRのエキスパートグループではお互いに情報交換を行いながら矛盾が生じないように仕様の策定を進めているという。なお、これらのJSRの違いについてはJSR 291のスペックリードであるGlyn Normington氏のブログに解説が掲載されている。