Jigsaw のお勉強 その3

Java

Jigsaw のお勉強の続きです。

超スローペースですがゆっくり慌てず三歩進んで二歩下がるような感じでもう暫く進めていこうと思っています。

今回は、最新Java情報局 「Java SE 9を先取り、Project Jigsawでモジュールを作成する」の写経をおこなってみました。

プログラムは同じではないのですがProject Jigsawで実現される機能の確認は同様にしました。

元記事で解説されているようにモジュールの定義は次のようになっています。

モジュールは複数のパッケージやリソースなどを含む、自己記述可能なコードの集合

今までの JARファイルにモジュール名が付いて依存性や公開範囲を記述できるようになったようです。

詳しくは元記事を参照してくださいませ。

では、モジュールを作っていきます。

プログラムを起動したら挨拶(文字列)を表示させるだけのプログラムです。

挨拶を表示させるためのインタフェースとしてGreetingインタフェース、その実装クラスとしてMultilingualGreetingクラスを作成します。

実装クラスのMultilingualGreetingクラスは日本語の挨拶か英語の挨拶をランダムに返します。

MultilingualGreetingクラスは外部からアクセスされることを避けるようにします。(Java SE 9 からインターフェイスにprivateメソッドが記述できるようになったのは今回は忘れてください。)

このアプリケーションをモジュールとするためにmodule-info.javaをトップディレクトリに作成します。

exports jp.yucchi.greeting;とmodule-info.javaに記述されています。

これは公開範囲を定義しています。

jp.yucchi.greeting.internalパッケージは公開されてないので外部からアクセスすることはできません。

それではjp.yucchi.greetingモジュールを使用するモジュールを作成します。

続いてこちらもモジュールとするためにmodule-info.javaを作成します。

先程作成したjp.yucchi.greetingモジュールを使用するためにrequires jp.yucchi.greeting;と記述しています。

これは依存性の定義となります。

面白いのはexports jp.yucchi.helloと自分自身を公開すると定義しています。

Helloクラスのmain()メソッドをコールすることも外部アクセスとなるからです。

これでシンプルなお試しプログラムが完成しました。

ディレクトリ構造は前回までと少し変更しています。

1

それぞれコンパイルしてみましょう。

binディレクトリを作成してコンパイルされたファイルを配置しました。

2

それでは確認のためにプログラムを実行してみます。

3

ちゃんとうごきましたね!(^_^)

それではモジュラーJARとしてパッケージ化してみましょう。

modsディレクトリを作成してモジュラーJARとしてパッケージングし配置しました。

4

一応できているみたいですが正しくできているか念の為に確認します。

5

モジュラーJARの依存性、公開範囲、メインクラスなどの情報に間違いが無いことを確認することができました。

依存性の定義にjava.baseモジュールがありますがこれはjava.lang.Objectクラスなどが含まれた必要不可欠なもので全てのモジュールに含まれることになります。

greeting@1.0.jarでは非公開パッケージがcontains jp.yucchi.greeting.internalと表示されています。

ここでJava SE 9からjarコマンドが少し変更されているのでヘルプをみておきましょう。

yucchi@ubuntu:~/Documents/MyJigsawProjects/HelloJigsaw$ jar –help
使用方法: jar [OPTION…] [ [–release VERSION] [-C dir] files] …
jarはクラスおよびリソースのアーカイブを作成し、アーカイブから個々のクラスまたは
リソースを操作または復元できます。

例:
# 2つのクラス・ファイルを含むclasses.jarというアーカイブを作成する:
jar –create –file classes.jar Foo.class Bar.class
# foo/のすべてのファイルを含む、既存のマニフェストを使用したアーカイブを作成する:
jar –create –file classes.jar –manifest mymanifest -C foo/ .
# モジュラjarアーカイブを作成する。モジュール・ディスクリプタはclasses/module-info.classに
# ある:
jar –create –file foo.jar –main-class com.foo.Main –module-version 1.0
     -C foo/ classes resources
# 既存の非モジュラjarをモジュラjarに更新する:
jar –update –file foo.jar –main-class com.foo.Main –module-version 1.0
     -C foo/ module-info.class
# 複数リリースjarを作成し、一部のファイルをMETA-INF/versions/9ディレクトリに配置する:
jar –create –file mr.jar -C foo classes –release 9 -C foo9 classes

jarコマンドを短縮または簡略化するには、個別のテキスト・ファイルで引数を指定し、
記号(@)を接頭辞として使用してjarコマンドに渡します。

例:
# 追加オプションおよびクラス・ファイルのリストをファイルclasses.listから読込みます
jar –create –file my.jar @classes.list

メイン操作モード:

  -c、–create               アーカイブを作成します
  -i,、–generate-index=FILE  指定のjarアーカイブの索引情報を
                             生成します
  -t、–list                 アーカイブの内容を一覧表示します
  -u、–update               既存のjarアーカイブを更新します
  -x、–extract              指定の(またはすべての)ファイルをアーカイブから抽出します
  -d, –describe-module      モジュール・ディスクリプタまたは自動モジュール名を出力します

どのモードでも有効な操作修飾子:

  -C DIR                     指定のディレクトリに変更し、次のファイルを
                             取り込みます
  -f、–file=FILE            アーカイブ・ファイル名。省略した場合、stdinまたは
                             stdoutのいずれかが操作に基づいて使用されます
      –release VERSION      次のすべてのファイルをjarのバージョニングされたディレクトリ
                             (つまり、META-INF/versions/VERSION/)に配置します
  -v、–verbose              標準出力に詳細な出力を生成します

作成または更新モードでのみ有効な操作修飾子:

  -e、–main-class=CLASSNAME モジュラまたは実行可能なjarアーカイブに
                             バンドルされたスタンドアロン・アプリケーションの
                             アプリケーション・エントリ・ポイント
  -m、–manifest=FILE        指定のマニフェスト・ファイルからマニフェスト情報を
                             取り込みます
  -M、–no-manifest          エントリのマニフェスト・ファイルを作成しません
      –module-version=VERSION    モジュラjarの作成時または非モジュラjarの更新時の
                             モジュール・バージョン
      –hash-modules=PATTERN モジュラjarの作成時または非モジュラjarの更新時に
                             指定のパターンに一致し、直接または間接的に
                             依存しているモジュールのハッシュを
                             計算および記録します
  -p、–module-path          ハッシュを生成するモジュール依存性
                             の場所

作成、更新および索引生成モードでのみ有効な操作修飾子:

  -0, –no-compress          格納のみ。ZIP圧縮を使用しません

その他のオプション:

  -h、–help[:compat]        これ(オプションで互換性)をhelpに指定します
      –help-extra           追加オプションのヘルプを提供します
      –version              プログラム・バージョンを出力します

モジュール・ディスクリプタ’module-info.class’が指定のディレクトリのルートまたは
jarアーカイブ自体のルートにある場合、アーカイブはモジュラjarです。
次の操作は、モジュラjarの作成時または既存の非モジュラjarの更新時に
のみ有効です:  ‘–module-version’、
‘–hash-modules’および’–module-path’。

ロング・オプションへの必須またはオプションの引数は、対応するショート・オプション
に対しても必須またはオプションになります。

Project Jigsawの影響でコマンドが増えていますね。(当たり前か・・・)

最後にこのプログラムを実行してみます。


java --module-path mods --module jp.yucchi.hello

6

アプリケーション・エントリ・ポイントを設定したモジュールのモジュールパスとモジュール名を指定してjavaコマンドによって実行します。

今回はモジュラーJAR作成時にアプリケーション・エントリ・ポイントを指定してますのでこのように実行できます。

モジュラーJAR作成時にアプリケーション・エントリ・ポイントを設定してない場合は次のように実行します。

モジュールのモジュールパスの指定はおなじです。

–module モジュール名/モジュールのメイン・クラス名とアプリケーション・エントリ・ポイント指定しなければいけません。

7

ついでだから javaコマンドのヘルプも確認しておきます。

 

yucchi@ubuntu:~/Documents/MyJigsawProjects/HelloJigsaw$ java –help
使用方法: java [options] <mainclass> [args…]
           (クラスを実行する場合)
   または  java [options] -jar <jarfile> [args…]
           (jarファイルを実行する場合)
   または  java [options] -m <module>[/<mainclass>] [args…]
       java [options] –module <module>[/<mainclass>] [args…]
           (モジュールのメイン・クラスを実行する場合)

メイン・クラス-jar <jarfile>、-mまたは–module
<module>/<mainclass>に続く引数は、メイン・クラスへの引数として渡されます。

オプションは次のとおりです:

    -d32      推奨されていません。今後のリリースで削除される予定です
    -d64      推奨されていません。今後のリリースで削除される予定です
    -cp <ディレクトリおよびzip/jarファイルのクラス検索パス>
    -classpath <ディレクトリおよびzip/jarファイルのクラス検索パス>
    –class-path <ディレクトリおよびzip/jarファイルのクラス検索パス>
                  :区切りリスト(ディレクトリ、JARアーカイブ、
                  ZIPアーカイブ)で、クラス・ファイルの検索用。
    -p <module path>
    –module-path <module path>…
                  ディレクトリの:区切りリスト、各ディレクトリ
                  はモジュールのディレクトリです。
    –upgrade-module-path <module path>…
                  ディレクトリの:区切りリスト、各ディレクトリ
                  は、ランタイム・イメージ内のアップグレード可能な
                  モジュールを置換するモジュールのディレクトリです
    –add-modules <module name>[,<module name>…]
                  初期モジュールに加えて解決するルート・モジュール。
                  <module name>には次も指定できます: ALL-DEFAULT、ALL-SYSTEM、
                  ALL-MODULE-PATH.
    –list-modules
                  参照可能なモジュールをリストし終了します
    -d <module name>
    –describe-module <module name>
                  モジュールを説明し終了します
    –dry-run     VMを作成しメイン・クラスをロードしますが、メイン・メソッドは実行しません。
                  –dry-runオプションは、次の検証に役立つ場合があります:
                  モジュール・システム構成などのコマンド行オプション。
    –validate-modules
                  すべてのモジュールを検証し終了します
                  –validate-modulesオプションは、次の検索に役立つ場合があります:
                  モジュール・パス上のモジュールでの競合およびその他のエラー。
    -D<name>=<value>
                  システム・プロパティを設定します
    -verbose:[class|module|gc|jni]
                  詳細出力を有効にします
    -version      製品バージョンをエラー・ストリームに出力して終了します
    –version     製品バージョンを出力ストリームに出力して終了します
    -showversion  製品バージョンをエラー・ストリームに出力して続行します
    –show-version
                  製品バージョンを出力ストリームに出力して続行します
    –show-module-resolution
                  起動時にモジュール解決出力を表示します
    -? -h -help
                  このヘルプ・メッセージをエラー・ストリームに出力します
    –help        このヘルプ・メッセージを出力ストリームに出力します
    -X            追加オプションのヘルプをエラー・ストリームに出力します
    –help-extra  追加オプションのヘルプを出力ストリームに出力します
    -ea[:<packagename>…|:<classname>]
    -enableassertions[:<packagename>…|:<classname>]
                  指定した粒度でアサーションを有効にします
    -da[:<packagename>…|:<classname>]
    -disableassertions[:<packagename>…|:<classname>]
                  指定した粒度でアサーションを無効にします
    -esa | -enablesystemassertions
                  システム・アサーションを有効にします
    -dsa | -disablesystemassertions
                  システム・アサーションを無効にします
    -agentlib:<libname>[=<options>]
                  ネイティブ・エージェント・ライブラリ<libname>をロードします。例: -agentlib:jdwp
                  -agentlib:jdwp=helpも参照してください
    -agentpath:<pathname>[=<options>]
                  フルパス名を使用して、ネイティブ・エージェント・ライブラリをロードします
    -javaagent:<jarpath>[=<options>]
                  Javaプログラミング言語エージェントをロードします。java.lang.instrumentを参照してください
    -splash:<imagepath>
                  指定されたイメージを含むスプラッシュ画面を表示します
                  HiDPIスケールのイメージが自動的にサポートされて使用されます
                  (可能な場合)。スケーリングされないイメージのファイル名(image.extなど)を
                  引数として-splashオプションに必ず渡す必要があります。
                  指定された最も適切なスケーリング済イメージが選択されます
                  (自動的)。
                  詳細は、SplashScreen APIのドキュメントを参照してください
    @argumentファイル
                  オプションを含む1つ以上の引数ファイル
    -disable-@files
                  さらなる引数ファイル拡張を無効にします
長いオプションの引数を指定する場合、–<name>=<value>または
–<name> <value>を使用できます。

まとめ

今回は何も考えずにほぼ写経しただけなので随分楽に進みました。

しかし、モジュール化のメリットの依存性、公開範囲の制限を定義することを学ぶことができました。(^_^)

module-info.javaにrequiresとexportsを記述して依存と公開の定義をする。

requires モジュール名;とすることで指定したモジュールに依存することを定義します。

今回は使っていませんがrequires transient モジュール名;とすることで推移的依存(依存したモジュールの依存先も依存可能)を定義できます。

また、requires static モジュール名;とすることでコンパイル時のみ依存可能と定義できます。

ちょっと複雑に感じますが慣れてくると便利に依存を定義することができそうですね。

次に公開するパッケージを定義するのにexports パッケージ名;と記述します。

exports パッケージ名 to モジュール名;とすることで特定のモジュールに公開することが可能です。

 

ゆっくり少しずつだけどお勉強を進めていこう。

Jigsaw のお勉強 その1

Jigsaw のお勉強 その2

Hatena タグ: