桜庭さんのJAVA IN THE BOXの記事 に触発されて、JDK9で入る予定のProject Jigsawを触ってみました。
Project Jigsawとは
Project Jigsawの概要はここで説明されていました。私の理解では、
- 不要なライブラリを削ぎ落としたJDKを作ったり、
- Javaライブラリのアクセス可能性をより細かく設定したり
- publicクラスにしたら全てのクラスからアクセスできて嫌な感じですよね
というところを目的にしていると思っています。(「パフォーマンスの向上」というのは詳細不明)
また、Jigsawでは、JavaSEにモジュールシステム(module system)というものが導入されます。モジュールとは何ぞやというと、JSR 376によると、以下のように説明されています。
With a module system the packages of a component are grouped into a module that governs how they use other modules, and how other modules use them.
つまり、モジュールとはJavaのパッケージをまとめたもので、他のモジュールをどのように使うか、また他のモジュールからどのように使われるかを制御できるもののようです。
JDKでは、module-info.javaというソースファイルでモジュール間のアクセスを制御できます。
サンプルプログラム
クイックスタートを写経してみました。
呼び出される側のモジュールのソースコード
module org.astro {
exports org.astro;
}
これは、他のモジュールから、org.astroモジュールに含まれるorg.astroパッケージのpublicクラスのみアクセス可能であることを表します。モジュール名とパッケージ名が同じでややこしいですが、こういう規約でもあるんでしょうかね。
package org.astro;
public class World {
public static String name() {
return "world";
}
}
呼び出す側のモジュール
module com.greetings {
requires org.astro;
}
これは、com.greetingsモジュールが、org.astroモジュールに依存していることを表します。依存しているというのは、com.greetingsモジュールのコンパイル時、あるいは実行時に、org.astroモジュールがモジュールパス上に存在する必要があるということです。
package com.greetings;
import org.astro.World;
public class Main {
public static void main(String[] args) {
System.out.format("Greetings %s!%n", World.name());
}
}
コンパイル
以下のJavaを使用しました。
>java -version
java version "9-ea"
Java(TM) SE Runtime Environment (build 9-ea+103-jigsaw-nightly-h4374-20160202)
Java HotSpot(TM) Client VM (build 9-ea+103-jigsaw-nightly-h4374-20160202, mixed mode)
コンパイル方法は以下。org.astroモジュールをコンパイルした後、com.greetingsモジュールをコンパイルしてます。
>javac -d mods\org.astro src\org.astro\module-info.java src\org.astro\org\astro\World.java
>javac -mp mods -d mods\com.greetings src\org.greetings\module-info.java src\org.greetings\com\greetings\Main.java
実は、一度に全てのソースコードをコンパイルできるとクイックスタートにはあるのですが、実際にはなぜかできなかった。Windowsだから?
>javac -d mods -modulesourcepath src src\org.astro\module-info.java src\org.astro\org\astro\World.java src\org.greetings\module-info.java src\org.greetings\com\greetings\Main.java
src\org.greetings\module-info.java:1: エラー: module name com.greetings does not match expected name org.greetings
module com.greetings {
^
エラー1個
実行
>java -mp mods -m com.greetings/com.greetings.Main
Greetings world!
ちゃんと実行できました!
実行対象は、
<モジュール名>/<パッケージパス>.<クラス名>
というように指定します。
パッケージング
モジュールを1つのファイル(jarファイル)にパッケージ化して使用することもできます。
>jar --create --file=mlib\org.astro@1.0.jar --module-version=1.0 -C mods\org.astro .
>jar --create --file=mlib\com.greetings.jar --main-class=com.greetings.Main -C mods\com.greetings .
>dir mlib
com.greetings.jar
org.astro@1.0.jar
モジュールのjarファイルにモジュールパスを通して実行することもできます。ただし、通す先はjarファイルではなくjarファイルの置いてあるディレクトリでOKでした。
>java -mp mlib -m com.greetings/com.greetings.Main
Greetings world!
モジュールの概要を表示してみます。
>jar --print-module-descriptor --file=mlib\org.astro@1.0.jar
Name:
org.astro@1.0
Requires:
java.base [ MANDATED ]
Exports:
org.astro
org.astroモジュールは、java.baseモジュール(Javaプログラムが動作するために必須のモジュール)に依存していて、module-info.javaに書いたようにorg.astroモジュールを公開しています。
>jar --print-module-descriptor --file=mlib\com.greetings.jar
Name:
com.greetings
Requires:
java.base [ MANDATED ]
org.astro
Main class:
com.greetings.Main
Conceals:
com.greetings
一方、com.greetingsモジュールはorg.astroモジュールにも依存しています。また、jarファイルを作るときにメインクラスも指定したため表示されていますね。Concealsは非公開パッケージですかね。(全部出るのかな?)
もちろん、依存するパッケージがなければ、実行に(コンパイルも)失敗します。
>dir mlib2
com.greetings.jar
>java -mp mlib2 -m com.greetings
Error occurred during initialization of VM
java.lang.module.ResolutionException: Module org.astro not found, required by com.greetings
at java.lang.module.Resolver.fail(java.base@9-ea/Resolver.java:860)
at java.lang.module.Resolver.resolve(java.base@9-ea/Resolver.java:351)
at java.lang.module.Resolver.resolve(java.base@9-ea/Resolver.java:305)
at java.lang.module.Configuration.resolve(java.base@9-ea/Configuration.java:249)
at jdk.internal.module.ModuleBootstrap.boot(java.base@9-ea/ModuleBootstrap.java:188)
at java.lang.System.initPhase2(java.base@9-ea/System.java:1917)
今日はここまで。