Help us understand the problem. What is going on with this article?

JDK9 Jigsaw を試してみた

More than 3 years have passed since last update.

桜庭さんの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というソースファイルでモジュール間のアクセスを制御できます。

サンプルプログラム

クイックスタートを写経してみました。

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

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

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

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モジュールがモジュールパス上に存在する必要があるということです。

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)

今日はここまで。

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away