Project Jigsaw ことはじめ(その2)
Project Jigsaw ことはじめ - torutkのブログ の続きです。
今日は、JDK8 Jigsawプレビューが更新された件、および、2つの依存関係のあるモジュールを作成し、ライブラリ化、実行する件を紹介します。
JDK8 Jigsawプレビューの更新
JDK8 Jigsawプレビューが1か月ちょっとぶりに更新されました(2012/6/22付でb36→b42ベースに)。
展開しJavaのバージョンを表示させると次のとおりです。
$ java -version java version "1.8.0-ea" Java(TM) SE Runtime Environment (build 1.8.0-ea-jigsaw-nightly-h458-20120622-b42-b00) Java HotSpot(TM) 64-Bit Server VM (build 24.0-b13, mixed mode)
モジュール・ライブラリにインストールしたモジュールを削除するためのサブコマンドremove(rm)がjmodに追加されています。その他の修正は把握していません(Changes一覧がないので・・・)。
$ jmod list -L lib org.example.bravo@1.0 org.example.delta@1.0 $ jmod remove -L lib org.example.bravo@1.0 $ $ jmod list -L lib org.example.delta@1.0 $
2つのモジュール(依存関係あり)の作成
今回は、依存関係を持つJigsawのモジュールを2つ作成し、モジュール・ライブラリにインストールして実行するところまで動かしてみます。
作成するモジュールは、
org.example.bravo@1.0 ↓ org.example.delta@1.0
です。
今回作成するディレクトリ構造は次のとおりです。
2ndJigsaw +-- build +-- lib +-- src +-- org.example.bravo | +-- module-info.java | +-- org | +-- example | +-- bravo | +-- HelloBravo.java +-- org.example.delta +-- module-info.java +-- org +-- example +-- delta +-- HelloDelta.java +-- impl + HelloDeltaImpl.java
org.example.deltaモジュールの作成
まずは依存される側から作成します。
src/org.example.delta/module-info.java
module org.example.delta @ 1.0 { exports org.example.delta; }
他のモジュールに公開するのは、org.example.deltaパッケージのHelloDeltaで、org.example.delta.implパッケージ(HelloDeltaImpl)は他のモジュールには非公開となります。
src/org.example.delta/org/exaple/delta/HelloDelta.java
package org.example.delta; import org.example.delta.impl.HelloDeltaImpl; public class HelloDelta { public static String greet() { return HelloDeltaImpl.greet(); } }
src/org.example.delta/org/exaple/delta/impl/HelloDeltaImpl.java
package org.example.delta.impl; public class HelloDeltaImpl { public static String greet() { return "Hello Delta"; } }
HelloDeltaクラスからHelloDeltaImplクラスを利用するためには、パッケージが異なるのでpublicなクラスである必要がありました。しかし、publicなクラスは他のどこからも参照できてしまいます。implパッケージはこのorg.example.deltaモジュールの中では自由に使用し、モジュールの外には隠蔽することが可能になります。
次に、このorg.example.deltaモジュールのコンパイルとモジュール・ライブラリへのインストールを行います。
$ javac -d ./build -modulepath ./build -sourcepath src \ `find ./src/org.example.delta -name "*.java"` $
$ jmod create -L lib $ jmod install -L lib ./build org.example.delta $ jmod ls -L lib org.example.delta@1.0 $
プログラムを修正して再度インストールするとき、同じモジュール名かつバージョン番号のものがモジュール・ライブラリに存在するとエラーになります。
$ jmod install -L lib ./build org.example.delta I/O error: org.openjdk.jigsaw.ConfigurationException: module view org.example.delta@1.0 already installed org.openjdk.jigsaw.cli.Command$Exception: I/O error: org.openjdk.jigsaw.ConfigurationException: module view org.example.delta@1.0 already installed at org.openjdk.jigsaw.cli.Librarian$Install.go(Librarian.java:211)
このときは、いったん削除してからインストールします。
$ jmod rm -L lib org.example.delta@1.0
org.example.bravoモジュールの作成
先に作ったorg.example.deltaを使用するモジュールを作成します。
src/org.example.bravo/module-info.java
module org.example.bravo @ 1.0 { requires org.example.delta; class org.example.bravo.HelloBravo; }
requires文で、使用する(依存する)モジュールを指定します。なお、バージョン番号を指定することもできます。この例では省略していますが、省略時は最新バージョンを使用するとあります。
また、プログラムの実行にあたってエントリポイントとなるmainを持つクラスを指定しています。
src/org.example.bravo/org/example/bravo/HelloBravo.java
package org.example.bravo; import org.example.delta.HelloDelta; public class HelloBravo { public static String greet() { return "hello Bravo, " + HelloDelta.greet(); } public static void main(String[] args) { System.out.println(HelloBravo.greet()); } }
このorg.example.bravoモジュールのコンパイルとモジュール・ライブラリへのインストールを行います。
$ javac -d ./build -modulepath ./build -sourcepath src \ `find ./src/org.example.bravo -name "*.java"` $
$ jmod install -L lib ./build org.example.bravo $ jmod ls -L lib org.example.bravo@1.0 org.example.delta@1.0
プログラムの実行
$ java -L lib -m org.example.bravo hello Bravo, Hello Delta Warning: CLASSPATH environment variable ignored when -m specified $
モジュールで公開されないクラスを使用
さきのHelloBravoクラスの中からHelloDeltaImplを直接呼出し
src/org.example.bravo/org/example/bravo/HelloBravo.java
package org.example.bravo; import org.example.delta.HelloDelta; import org.example.delta.impl.HelloDeltaImpl; public class HelloBravo { public static String greet() { return "hello Bravo, " + HelloDelta.greet(); } public static void main(String[] args) { System.out.println(HelloBravo.greet()); System.out.println(HelloDeltaImpl.greet()); } }
と、org.example.deltaモジュールで公開されていないクラスを使用するコードに修正します。
org.example.bravoを再度コンパイルしモジュール・ライブラリにインストールします。
$ javac -d ./build -modulepath ./build -sourcepath src \ `find ./src/org.example.bravo -name "*.java"` $ jmod rm -L lib org.example.bravo@1.0 $ jmod install -L lib org.example.bravo $
モジュールのインストールまでは特にエラーもなく進んでしまいました。
では、実行してみると、エラーが出ます。が、実行時エラーとなっています。
$ java -L lib -m org.example.bravo hello Bravo, Hello Delta Exception in thread "main" java.lang.NoClassDefFoundError: org/example/delta/impl/HelloDeltaImpl at org.example.bravo.HelloBravo.main(HelloBravo.java:13) Caused by: java.lang.ClassNotFoundException: org.example.delta.impl.HelloDeltaImpl : requested by +org.example.bravo at org.openjdk.jigsaw.Loader.loadClass(Loader.java:116) at java.lang.ClassLoader.loadClass(ClassLoader.java:357) ... 1 more Warning: CLASSPATH environment variable ignored when -m specified $
公開されていないパッケージをrequire
次のパターンとして、org.example.bravoのモジュール定義でorg.example.delta.implを指定してみます。
src/org.example.bravo/module-info.java
module org.example.bravo @ 1.0 { requires org.example.delta; requires org.example.delta.impl; class org.example.bravo.HelloBravo; }
コンパイルします。
$ javac -d ./build -modulepath ./build -sourcepath src \ `find ./src/org.example.bravo -name "*.java"` エラー: Cannot resolve module dependencies using Jigsaw module resolver org.example.bravo@=1.0: Cannot resolve エラー1個
今度は、コンパイル時に未解決の依存関係があるとのエラーとなりました。
補足事項
バージョン番号を指定しないmoduleでmainのエントリポイントを定義しているものがjmod installでエラーになる
$ jmod install -L lib build org.example.alfa $ jmod install -L lib build org.example.alfa Exception in thread "main" java.lang.NullPointerException at java.lang.module.ModuleId.toQuery(ModuleId.java:102) at org.openjdk.jigsaw.SimpleLibrary.configureWhileModuleDirectoryLocked(SimpleLibrary.java:1691) at org.openjdk.jigsaw.SimpleLibrary.installFromManifests(SimpleLibrary.java:1125) at org.openjdk.jigsaw.cli.Librarian$Install.go(Librarian.java:207) at org.openjdk.jigsaw.cli.Librarian$Install.go(Librarian.java:186) at org.openjdk.jigsaw.cli.Command.run(Command.java:100) at org.openjdk.jigsaw.cli.Librarian.exec(Librarian.java:693) at org.openjdk.jigsaw.cli.Librarian.run(Librarian.java:591) at org.openjdk.jigsaw.cli.Librarian.main(Librarian.java:717)
エントリポイントを指定していないものについてはエラーになりません。
依存関係上、削除すると影響のあるモジュールがある場合、jmod removeはエラーになる
$ jmod ls -L lib org.example.bravo@1.0 org.example.delta@1.0 $ jmod rm -L lib org.example.delta@1.0 org.openjdk.jigsaw.ConfigurationException: org.example.delta@1.0: being used by org.example.bravo@1.0 :
と、他のモジュールから使用されているためエラーとなりました。