Project Jigsaw ことはじめ(その2) - torutkのブログ の続きです。
前回、2つの依存関係のある次のモジュールから構成されるサンプルプログラムを作成し、依存関係の他、モジュールレベルでの非公開クラスへのアクセスの対応を実験してみました。
- org.example.bravo
- org.example.delta
今回は、org.example.deltaモジュールをバージョン番号を変え、複数のバージョンをライブラリにインストールし、どちらが使われるのか実験をします。
org.example.deltaの新しいバージョンを作成
バージョンを1.1としたモジュール定義ファイルに修正します。
src/org.example.delta/module-info.java
module org.example.delta @ 1.1 { exports org.example.delta; }
モジュールのバージョン番号箇所だけ変更(1.0→1.1)しました。
次にソースファイルを修正します。
src/org.example.delta/org/example/delta/impl/HelloDeltaImpl.java
package org.example.delta.impl; public class HelloDeltaImpl { public static String greet() { return "Hello Delta 1.1"; } }
greetの戻り値となる文字列を修正しました。
コンパイルします。
$ javac -d ./build -modulepath ./build -sourcepath src `find ./src -name "*.java"` $
新しいバージョンをモジュール・ライブラリにインストールします。
前回の続きですから、現時点は次のモジュールがインストール済みの状態です。
$ jmod ls -L lib org.example.bravo@1.0 org.example.delta@1.0
org.example.deltaの新しいバージョンをモジュール・ライブラリにインストールします。
$ jmod install -L lib ./build org.example.delta $ jmod ls -L lib org.example.bravo@1.0 org.example.delta@1.0 org.example.delta@1.1 $
org.example.bravoが依存するorg.example.deltaが2つモジュール・ライブラリに存在します。どちらが使われるのか、さっそく実行してみます。
$ java -L lib -m org.example.bravo hello Bravo, Hello Delta 1.1 Warning: CLASSPATH environment variable ignored when -m specified $
org.example.bravo自体はモジュール・ライブラリに先にインストールしていたまま、変更はしていません。しかし、org.example.deltaの後からインストールしたバージョン1.1を呼び出しています。
org.example.bravoのモジュール定義から、requires文を抜粋します。
requires org.example.delta;
バージョンを省略しているので、モジュール・リポジトリにあるorg.example.deltaのうち最新バージョンのものを使用します。
ここで、org.example.delta@1.1を削除しようとすると、
$ jmod rm -L lib org.example.delta@1.1 org.openjdk.jigsaw.ConfigurationException: org.example.delta@1.1: being used by org.example.bravo@1.0 : $
と、使用しているモジュールがあるためエラーとなります。
では、古いバージョンであるorg.example.delta@1.0を削除しようとすると
$ jmod rm -L lib org.example.delta@1.0 $ jmod ls -L lib org.example.bravo@1.0 org.example.delta@1.1
と問題なく削除されました。
org.example.bravoが依存するorg.example.deltaのバージョン指定
org.example.deltaのバージョンを更新していくといずれorg.example.bravoと整合がとれなくなります。そこで、最新版ではなく、整合の取れるバージョンを指定してみることにしました。
src/org.example.bravo/module-info.java
module org.example.bravo @ 1.0 { requires org.example.delta @ < 2.0; class org.example.bravo.HelloBravo; }
バージョン番号として、1.xを許容したいので、< 2.0を指定しました。
org.example.bravoをコンパイルします。
$ javac -d ./build -modulepath ./build -sourcepath src `find ./src -name "*.java"`
モジュール・ライブラリの内容を確認します。
$ jmod ls -L lib org.example.bravo@1.0 org.example.delta@1.1 $
org.example.bravoをいったんモジュール・ライブラリから削除します。
$ jmod rm -L lib org.example.bravo@1.0
org.example.bravoをモジュール・ライブラリにインストールします。
$ jmod install -L lib ./build org.example.bravo
$ java -L lib -m org.example.bravo hello Bravo, Hello Delta 1.1 Warning: CLASSPATH environment variable ignored when -m specified
org.example.deltaのバージョンアップ
org.example.deltaに、互換性のないAPI変更を伴う修正を入れます。
src/org.example.delta/module-info.java
module org.example.delta @ 2.0 { exports org.example.delta; }
バージョンを2.0にしました。
src/org.example.delta/HelloDelta.java
package org.example.delta; import org.example.delta.impl.HelloDeltaImpl; public class HelloDelta { public static String getGreeting() { return HelloDeltaImpl.greet(); } }
org.example.bravoから呼ばれるAPIを互換性のない変更をしています。
- (修正前)public static String greet()
- (修正後)public static String getGreeting()
org.example.deltaをコンパイルします。
$ javac -d ./build -modulepath ./build -sourcepath src `find ./src/org.example.delta -name "*.java"`
org.example.deltaをインストールします。
$ jmod install -L lib build org.example.delta $ jmod ls -L lib org.example.bravo@1.0 org.example.delta@1.1 org.example.delta@2.0 $
org.example.bravoを実行します。
$ java -L lib -m org.example.bravo hello Bravo, Hello Delta 1.1 Warning: CLASSPATH environment variable ignored when -m specified
バージョン番号を指定していたので、エラーになることなく実行できました。
(詳細)Jigsaw モジュールのバージョン番号
バージョン番号の記述方法については、次のURLにBNF風記法の記載があります。
これによると、requires文のモジュール名とバージョン番号の指定の書式は
ModuleNameAndVersionQuery: ModuleName [@ VersionQuery] VersionQuery: [Operator] VersionLiteral VersionLiteral: JavaDigit VersionLiteralChars VersionLiteralChars: VersionLiteralChar VersionLiteralChars VersionLiteralChar VersionLiteralChar: JavaLetterOrDigit . -
とあります。バージョン番号の文字列は、先頭が数字(JavaDigit)で、以降は文字・数字、ピリオド、ハイフンが続くものです。1.2.3-1 や、2.3-preview などは合致します。
OperatorについてはBNF風定義には見当たりませんでした。本文中にある記載は、
The operator in a version query must be <<, <=, =, >=, or >>, or a compile-time error occurs.
とあります。ただし、<< を指定したらエラーとなり、 < を指定することで回避できます。