JDK9 Jigsaw を試してみた

桜庭さんのJAVA IN THE BOXの[記事](http://www.javainthebox.com/2015/12/jre-jlin.html) に触発されて、JDK9で入る予定のProject Jigsawを触ってみました。

# Project Jigsawとは

Project Jigsawの概要は[ここ](http://openjdk.java.net/projects/jigsaw/)で説明されていました。私の理解では、

- 不要なライブラリを削ぎ落としたJDKを作ったり、
- Javaライブラリのアクセス可能性をより細かく設定したり
    - publicクラスにしたら全てのクラスからアクセスできて嫌な感じですよね

というところを目的にしていると思っています。(「パフォーマンスの向上」というのは詳細不明)

また、Jigsawでは、JavaSEにモジュールシステム(module system)というものが導入されます。モジュールとは何ぞやというと、[JSR 376](https://www.jcp.org/en/jsr/detail?id=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というソースファイルでモジュール間のアクセスを制御できます。

# サンプルプログラム

[クイックスタート](http://openjdk.java.net/projects/jigsaw/quick-start)を写経してみました。

## 呼び出される側のモジュールのソースコード

```java:src/org.astro/module-info.java
module org.astro {
  exports org.astro;
}
```

これは、他のモジュールから、org.astroモジュールに含まれるorg.astroパッケージのpublicクラスのみアクセス可能であることを表します。モジュール名とパッケージ名が同じでややこしいですが、こういう規約でもあるんでしょうかね。

```java:src/org.astro/org/astro/World.java
package org.astro;

public class World {
  public static String name() {
    return "world";
  }
}
```

## 呼び出す側のモジュール

```src/org.greetings/module-info.java
module com.greetings {
  requires org.astro;
}
```

これは、com.greetingsモジュールが、org.astroモジュールに依存していることを表します。依存しているというのは、com.greetingsモジュールのコンパイル時、あるいは実行時に、org.astroモジュールがモジュールパス上に存在する必要があるということです。

```java:src/org.greetings/com/greetings/Main.java
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)
```

今日はここまで。